170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan/*
270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * Copyright (C) 2016 The Android Open Source Project
370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan *
470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * Licensed under the Apache License, Version 2.0 (the "License");
570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * you may not use this file except in compliance with the License.
670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * You may obtain a copy of the License at
770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan *
870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan *      http://www.apache.org/licenses/LICENSE-2.0
970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan *
1070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * Unless required by applicable law or agreed to in writing, software
1170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * distributed under the License is distributed on an "AS IS" BASIS,
1270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * See the License for the specific language governing permissions and
1470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * limitations under the License.
1570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan */
1670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanpackage com.android.server.wifi.util;
1770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
1870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport android.util.Log;
1970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
2070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport com.android.server.wifi.WifiLoggerHal;
2170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
2270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport java.nio.BufferUnderflowException;
2370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport java.nio.ByteBuffer;
2470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport java.nio.ByteOrder;
2570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport java.util.HashSet;
2670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanimport java.util.Set;
2770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
2870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan/**
2970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * This class parses the raw bytes of a network frame, and stores the parsed information in its
3070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan * public fields.
3170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan */
3270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tanpublic class FrameParser {
3370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    /**
3470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * Note: When adding constants derived from network protocol specifications, please encode
3570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * these constants the same way as the relevant specification, for ease of comparison.
3670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     */
3770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
3870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final String TAG = "FrameParser";
3970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
4070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    /* These fields hold the information parsed from this frame. */
4170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    public String mMostSpecificProtocolString = "N/A";
4270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    public String mTypeString = "N/A";
435e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    public String mResultString = "N/A";
4470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
4570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    /**
4670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * Parses the contents of a given network frame.
4770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     *
4870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * @param frameType The type of the frame, as defined in
4970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * {@link com.android.server.wifi.WifiLoggerHal}.
5070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * @param frameBytes The raw bytes of the frame to be parsed.
5170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     */
5270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    public FrameParser(byte frameType, byte[] frameBytes) {
5370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        try {
5470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            ByteBuffer frameBuffer = ByteBuffer.wrap(frameBytes);
5570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            frameBuffer.order(ByteOrder.BIG_ENDIAN);
5670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            if (frameType == WifiLoggerHal.FRAME_TYPE_ETHERNET_II) {
5770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseEthernetFrame(frameBuffer);
5870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            } else if (frameType == WifiLoggerHal.FRAME_TYPE_80211_MGMT) {
5970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseManagementFrame(frameBuffer);
6070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            }
6170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        } catch (BufferUnderflowException | IllegalArgumentException e) {
6270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Dissection aborted mid-frame: " + e);
6370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
6470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
6570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
6670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    /**
6770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * Read one byte into a form that can easily be compared against, or output as, an integer
6870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * in the range (0, 255).
6970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     */
7070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static short getUnsignedByte(ByteBuffer data) {
7170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        return (short) (data.get() & 0x00ff);
7270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
7370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    /**
7470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * Read two bytes into a form that can easily be compared against, or output as, an integer
7570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     * in the range (0, 65535).
7670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan     */
7770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static int getUnsignedShort(ByteBuffer data) {
7870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        return (data.getShort() & 0xffff);
7970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
8070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
8170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final int ETHERNET_SRC_MAC_ADDR_LEN = 6;
8270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final int ETHERNET_DST_MAC_ADDR_LEN = 6;
8370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ETHERTYPE_IP_V4 = (short) 0x0800;
8470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ETHERTYPE_ARP = (short) 0x0806;
8570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ETHERTYPE_IP_V6 = (short) 0x86dd;
8670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ETHERTYPE_EAPOL = (short) 0x888e;
8770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
8870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseEthernetFrame(ByteBuffer data) {
8970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "Ethernet";
9070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + ETHERNET_SRC_MAC_ADDR_LEN + ETHERNET_DST_MAC_ADDR_LEN);
9170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short etherType = data.getShort();
9270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (etherType) {
9370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ETHERTYPE_IP_V4:
9470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseIpv4Packet(data);
9570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
9670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ETHERTYPE_ARP:
9770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseArpPacket(data);
9870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
9970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ETHERTYPE_IP_V6:
10070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseIpv6Packet(data);
10170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
10270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ETHERTYPE_EAPOL:
10370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseEapolPacket(data);
10470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
10570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
10670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
10770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
10870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
10970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
11070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_VERSION_BYTE_MASK = (byte) 0b11110000;
11170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_IHL_BYTE_MASK = (byte) 0b00001111;
11270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_ADDR_LEN = 4;
11370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_DSCP_AND_ECN_LEN = 1;
11470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_TOTAL_LEN_LEN = 2;
11570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_ID_LEN = 2;
11670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_FLAGS_AND_FRAG_OFFSET_LEN = 2;
11770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_TTL_LEN = 1;
11870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_HEADER_CHECKSUM_LEN = 2;
11970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_SRC_ADDR_LEN = 4;
12070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V4_DST_ADDR_LEN = 4;
12170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_PROTO_ICMP = 1;
12270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_PROTO_TCP = 6;
12370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_PROTO_UDP = 17;
12470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BYTES_PER_QUAD = 4;
12570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
12670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseIpv4Packet(ByteBuffer data) {
12770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "IPv4";
12870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.mark();
12970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        byte versionAndHeaderLen = data.get();
13070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int version = (versionAndHeaderLen & IP_V4_VERSION_BYTE_MASK) >> 4;
13170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (version != 4) {
13270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "IPv4 header: Unrecognized protocol version " + version);
13370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
13470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
13570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
13670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + IP_V4_DSCP_AND_ECN_LEN + IP_V4_TOTAL_LEN_LEN
13770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + IP_V4_ID_LEN + IP_V4_FLAGS_AND_FRAG_OFFSET_LEN + IP_V4_TTL_LEN);
13870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short protocolNumber = getUnsignedByte(data);
13970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + IP_V4_HEADER_CHECKSUM_LEN + IP_V4_SRC_ADDR_LEN
14070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + IP_V4_DST_ADDR_LEN);
14170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
14270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int headerLen = (versionAndHeaderLen & IP_V4_IHL_BYTE_MASK) * BYTES_PER_QUAD;
14370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.reset();  // back to start of IPv4 header
14470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + headerLen);
14570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
14670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (protocolNumber) {
14770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IP_PROTO_ICMP:
14870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseIcmpPacket(data);
14970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
15070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IP_PROTO_TCP:
15170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseTcpPacket(data);
15270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
15370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IP_PROTO_UDP:
15470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseUdpPacket(data);
15570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
15670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
15770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
15870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
15970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
16070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
16170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte TCP_SRC_PORT_LEN = 2;
16270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final int HTTPS_PORT = 443;
16370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final Set<Integer> HTTP_PORTS = new HashSet<>();
16470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    static {
16570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(80);
16670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(3128);
16770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(3132);
16870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(5985);
16970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(8080);
17070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(8088);
17170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(11371);
17270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(1900);
17370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(2869);
17470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        HTTP_PORTS.add(2710);
17570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
17670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
17770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseTcpPacket(ByteBuffer data) {
17870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "TCP";
17970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + TCP_SRC_PORT_LEN);
18070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int dstPort = getUnsignedShort(data);
18170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
18270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (dstPort == HTTPS_PORT) {
18370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString = "HTTPS";
18470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        } else if (HTTP_PORTS.contains(dstPort)) {
18570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString = "HTTP";
18670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
18770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
18870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
18970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte UDP_PORT_BOOTPS = 67;
19070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte UDP_PORT_BOOTPC = 68;
19170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte UDP_PORT_NTP = 123;
19270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte UDP_CHECKSUM_LEN = 2;
19370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
19470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseUdpPacket(ByteBuffer data) {
19570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "UDP";
19670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int srcPort = getUnsignedShort(data);
19770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int dstPort = getUnsignedShort(data);
19870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int length = getUnsignedShort(data);
19970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
20070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + UDP_CHECKSUM_LEN);
20170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if ((srcPort == UDP_PORT_BOOTPC && dstPort == UDP_PORT_BOOTPS)
20270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                || (srcPort == UDP_PORT_BOOTPS && dstPort == UDP_PORT_BOOTPC)) {
20370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            parseDhcpPacket(data);
20470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
20570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
20670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (srcPort == UDP_PORT_NTP || dstPort == UDP_PORT_NTP) {
20770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mMostSpecificProtocolString = "NTP";
20870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
20970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
21070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
21170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
21270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_OPCODE_LEN = 1;
21370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_HWTYPE_LEN = 1;
21470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_HWADDR_LEN_LEN = 1;
21570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_HOPCOUNT_LEN = 1;
21670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_TRANSACTION_ID_LEN = 4;
21770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_ELAPSED_SECONDS_LEN = 2;
21870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_FLAGS_LEN = 2;
21970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_CLIENT_HWADDR_LEN = 16;
22070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_SERVER_HOSTNAME_LEN = 64;
22170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short BOOTP_BOOT_FILENAME_LEN = 128;
22270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BOOTP_MAGIC_COOKIE_LEN = 4;
22370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short DHCP_OPTION_TAG_PAD = 0;
22470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short DHCP_OPTION_TAG_MESSAGE_TYPE = 53;
22570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short DHCP_OPTION_TAG_END = 255;
22670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
22770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseDhcpPacket(ByteBuffer data) {
22870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "DHCP";
22970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + BOOTP_OPCODE_LEN + BOOTP_HWTYPE_LEN + BOOTP_HWADDR_LEN_LEN
23070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + BOOTP_HOPCOUNT_LEN + BOOTP_TRANSACTION_ID_LEN + BOOTP_ELAPSED_SECONDS_LEN
23170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + BOOTP_FLAGS_LEN + IP_V4_ADDR_LEN * 4 + BOOTP_CLIENT_HWADDR_LEN
23270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + BOOTP_SERVER_HOSTNAME_LEN + BOOTP_BOOT_FILENAME_LEN + BOOTP_MAGIC_COOKIE_LEN);
23370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        while (data.remaining() > 0) {
23470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            short dhcpOptionTag = getUnsignedByte(data);
23570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            if (dhcpOptionTag == DHCP_OPTION_TAG_PAD) {
23670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                continue;
23770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            }
23870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            if (dhcpOptionTag == DHCP_OPTION_TAG_END) {
23970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
24070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            }
24170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            short dhcpOptionLen = getUnsignedByte(data);
24270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            switch (dhcpOptionTag) {
24370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                case DHCP_OPTION_TAG_MESSAGE_TYPE:
24470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                    if (dhcpOptionLen != 1) {
24570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                        Log.e(TAG, "DHCP option len: " + dhcpOptionLen  + " (expected |1|)");
24670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                        return;
24770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                    }
24870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                    mTypeString = decodeDhcpMessageType(getUnsignedByte(data));
24970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                    return;
25070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                default:
25170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                    data.position(data.position() + dhcpOptionLen);
25270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            }
25370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
25470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
25570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
25670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
25770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
25870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
25970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
26070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_ACK = 5;
26170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_NAK = 6;
26270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
26370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
26470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
26570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static String decodeDhcpMessageType(short messageType) {
26670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (messageType) {
26770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_DISCOVER:
26870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Discover";
26970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_OFFER:
27070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Offer";
27170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_REQUEST:
27270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Request";
27370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_DECLINE:
27470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Decline";
27570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_ACK:
27670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Ack";
27770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_NAK:
27870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Nak";
27970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_RELEASE:
28070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Release";
28170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case DHCP_MESSAGE_TYPE_INFORM:
28270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Inform";
28370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
28470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return "Unknown type " + messageType;
28570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
28670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
28770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
28870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ICMP_TYPE_ECHO_REPLY = 0;
28970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ICMP_TYPE_DEST_UNREACHABLE = 3;
29070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ICMP_TYPE_REDIRECT = 5;
29170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ICMP_TYPE_ECHO_REQUEST = 8;
29270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
29370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseIcmpPacket(ByteBuffer data) {
29470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "ICMP";
29570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short messageType = getUnsignedByte(data);
29670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (messageType) {
29770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_TYPE_ECHO_REPLY:
29870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Echo Reply";
29970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
30070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_TYPE_DEST_UNREACHABLE:
30170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Destination Unreachable";
30270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
30370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_TYPE_REDIRECT:
30470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Redirect";
30570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
30670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_TYPE_ECHO_REQUEST:
30770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Echo Request";
30870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
30970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
31070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Type " + messageType;
31170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
31270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
31370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
31470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
31570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_HWTYPE_LEN = 2;
31670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_PROTOTYPE_LEN = 2;
31770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_HWADDR_LEN_LEN = 1;
31870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_PROTOADDR_LEN_LEN = 1;
31970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_OPCODE_REQUEST = 1;
32070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte ARP_OPCODE_REPLY = 2;
32170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
32270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseArpPacket(ByteBuffer data) {
32370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "ARP";
32470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + ARP_HWTYPE_LEN + ARP_PROTOTYPE_LEN + ARP_HWADDR_LEN_LEN
32570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + ARP_PROTOADDR_LEN_LEN);
32670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int opCode = getUnsignedShort(data);
32770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (opCode) {
32870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ARP_OPCODE_REQUEST:
32970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Request";
33070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
33170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ARP_OPCODE_REPLY:
33270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Reply";
33370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                break;
33470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
33570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Operation " + opCode;
33670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
33770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
33870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
33970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V6_PAYLOAD_LENGTH_LEN = 2;
34070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V6_HOP_LIMIT_LEN = 1;
34170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V6_ADDR_LEN = 16;
34270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V6_HEADER_TYPE_HOP_BY_HOP_OPTION = 0;
34370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IP_V6_HEADER_TYPE_ICMP_V6 = 58;
34470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte BYTES_PER_OCT = 8;
34570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
34670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseIpv6Packet(ByteBuffer data) {
34770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "IPv6";
34870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int versionClassAndLabel = data.getInt();
34970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int version = (versionClassAndLabel & 0xf0000000) >> 28;
35070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (version != 6) {
35170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "IPv6 header: invalid IP version " + version);
35270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
35370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
35470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + IP_V6_PAYLOAD_LENGTH_LEN);
35570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
35670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short nextHeaderType = getUnsignedByte(data);
35770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + IP_V6_HOP_LIMIT_LEN + IP_V6_ADDR_LEN * 2);
35870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        while (nextHeaderType == IP_V6_HEADER_TYPE_HOP_BY_HOP_OPTION) {
35970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            int thisHeaderLen;
36070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            data.mark();
36170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            nextHeaderType = getUnsignedByte(data);
36270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            thisHeaderLen = (getUnsignedByte(data) + 1) * BYTES_PER_OCT;
36370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            data.reset();  // back to start of this header
36470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            data.position(data.position() + thisHeaderLen);
36570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
36670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (nextHeaderType) {
36770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IP_V6_HEADER_TYPE_ICMP_V6:
36870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                parseIcmpV6Packet(data);
36970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
37070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
37170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Option/Protocol " + nextHeaderType;
37270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
37370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
37470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
37570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
37670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_ECHO_REQUEST = 128;
37770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_ECHO_REPLY = 129;
37870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_ROUTER_SOLICITATION = 133;
37970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_ROUTER_ADVERTISEMENT = 134;
38070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_NEIGHBOR_SOLICITATION = 135;
38170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_NEIGHBOR_ADVERTISEMENT = 136;
38270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short ICMP_V6_TYPE_MULTICAST_LISTENER_DISCOVERY = 143;
38370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
38470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseIcmpV6Packet(ByteBuffer data) {
38570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "ICMPv6";
38670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short icmpV6Type = getUnsignedByte(data);
38770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (icmpV6Type) {
38870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_ECHO_REQUEST:
38970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Echo Request";
39070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
39170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_ECHO_REPLY:
39270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Echo Reply";
39370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
39470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_ROUTER_SOLICITATION:
39570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Router Solicitation";
39670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
39770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_ROUTER_ADVERTISEMENT:
39870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Router Advertisement";
39970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
40070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_NEIGHBOR_SOLICITATION:
40170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Neighbor Solicitation";
40270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
40370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_NEIGHBOR_ADVERTISEMENT:
40470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Neighbor Advertisement";
40570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
40670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case ICMP_V6_TYPE_MULTICAST_LISTENER_DISCOVERY:
40770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "MLDv2 report";
40870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
40970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
41070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Type " + icmpV6Type;
41170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
41270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
41370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
41470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
41570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte EAPOL_TYPE_KEY = 3;
41670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte EAPOL_KEY_DESCRIPTOR_RSN_KEY = 2;
41770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte EAPOL_LENGTH_LEN = 2;
41870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short WPA_KEY_INFO_FLAG_PAIRWISE = (short) 1 << 3;  // bit 4
41970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short WPA_KEY_INFO_FLAG_INSTALL = (short) 1 << 6;  // bit 7
42070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final short WPA_KEY_INFO_FLAG_MIC = (short) 1 << 8;  // bit 9
42170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEYLEN_LEN = 2;
42270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_REPLAY_COUNTER_LEN = 8;
42370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEY_NONCE_LEN = 32;
42470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEY_IV_LEN = 16;
42570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEY_RECEIVE_SEQUENCE_COUNTER_LEN = 8;
42670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEY_IDENTIFIER_LEN = 8;
42770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte WPA_KEY_MIC_LEN = 16;
42870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
42970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private void parseEapolPacket(ByteBuffer data) {
43070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "EAPOL";
43170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short eapolVersion = getUnsignedByte(data);
43270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (eapolVersion < 1 || eapolVersion > 2) {
43370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Unrecognized EAPOL version " + eapolVersion);
43470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
43570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
43670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
43770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short eapolType = getUnsignedByte(data);
43870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (eapolType != EAPOL_TYPE_KEY) {
43970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Unrecognized EAPOL type " + eapolType);
44070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
44170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
44270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
44370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + EAPOL_LENGTH_LEN);
44470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short eapolKeyDescriptorType = getUnsignedByte(data);
44570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (eapolKeyDescriptorType != EAPOL_KEY_DESCRIPTOR_RSN_KEY) {
44670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Unrecognized key descriptor " + eapolKeyDescriptorType);
44770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
44870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
44970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
45070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        short wpaKeyInfo = data.getShort();
45170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_PAIRWISE) == 0) {
45270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString = "Group Key";
45370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        } else {
45470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString = "Pairwise Key";
45570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
45670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
45770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        // See goo.gl/tu8AQC for details.
45870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_MIC) == 0) {
45970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString += " message 1/4";
46070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
46170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
46270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
46370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_INSTALL) != 0) {
46470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString += " message 3/4";
46570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
46670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
46770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
46870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        data.position(data.position() + WPA_KEYLEN_LEN + WPA_REPLAY_COUNTER_LEN
46970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + WPA_KEY_NONCE_LEN + WPA_KEY_IV_LEN + WPA_KEY_RECEIVE_SEQUENCE_COUNTER_LEN
47070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                + WPA_KEY_IDENTIFIER_LEN + WPA_KEY_MIC_LEN);
47170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        int wpaKeyDataLen = getUnsignedShort(data);
47270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (wpaKeyDataLen > 0) {
47370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString += " message 2/4";
47470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        } else {
47570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            mTypeString += " message 4/4";
47670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
47770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
47870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
47970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_TYPE_MGMT = 0x00;
48070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_REQ = 0x00;
48170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_RESP = 0x01;
48270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_REQ = 0x04;
48370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_RESP = 0x05;
48470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_AUTH = 0x0b;
4855e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_FRAME_CTRL_FLAG_ORDER = (byte) (1 << 7); // bit 8
4865e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_DURATION_LEN = 2;
4875e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_ADDR1_LEN = 6;
4885e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_ADDR2_LEN = 6;
4895e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_ADDR3_LEN = 6;
4905e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_SEQUENCE_CONTROL_LEN = 2;
4915e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_HT_CONTROL_LEN = 4;
49270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
49370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static byte parseIeee80211FrameCtrlVersion(byte b) {
49470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        return (byte) (b & 0b00000011);
49570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
4965e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static byte parseIeee80211FrameCtrlType(byte b) {
49770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        return (byte) ((b & 0b00001100) >> 2);
49870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
49970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    private static byte parseIeee80211FrameCtrlSubtype(byte b) {
50070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        return (byte) ((b & 0b11110000) >> 4);
50170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
5025e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private void parseManagementFrame(ByteBuffer data) {  // 802.11-2012 Sec 8.3.3.1
5035e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        data.order(ByteOrder.LITTLE_ENDIAN);
5045e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
50570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        mMostSpecificProtocolString = "802.11 Mgmt";
5065e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        byte frameControlVersionTypeSubtype = data.get();
5075e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        byte ieee80211Version = parseIeee80211FrameCtrlVersion(frameControlVersionTypeSubtype);
50870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (ieee80211Version != 0) {
50970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Unrecognized 802.11 version " + ieee80211Version);
51070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
51170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
51270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
5135e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        byte ieee80211FrameType = parseIeee80211FrameCtrlType(frameControlVersionTypeSubtype);
51470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        if (ieee80211FrameType != IEEE_80211_FRAME_CTRL_TYPE_MGMT) {
51570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            Log.e(TAG, "Unexpected frame type " + ieee80211FrameType);
51670b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            return;
51770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
51870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan
5195e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        byte frameControlFlags = data.get();
5205e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5215e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        data.position(data.position() + IEEE_80211_DURATION_LEN + IEEE_80211_ADDR1_LEN
5225e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                + IEEE_80211_ADDR2_LEN + IEEE_80211_ADDR3_LEN + IEEE_80211_SEQUENCE_CONTROL_LEN);
5235e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5245e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        if ((frameControlFlags & IEEE_80211_FRAME_CTRL_FLAG_ORDER) != 0) {
5255e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            // Per 802.11-2012 Sec 8.2.4.1.10.
5265e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            data.position(data.position() + IEEE_80211_HT_CONTROL_LEN);
5275e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        }
5285e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5295e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        byte ieee80211FrameSubtype = parseIeee80211FrameCtrlSubtype(frameControlVersionTypeSubtype);
53070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        switch (ieee80211FrameSubtype) {
53170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_REQ:
53270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Association Request";
53370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
53470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_RESP:
53570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Association Response";
5365e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                parseAssociationResponse(data);
53770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
53870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_REQ:
53970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Probe Request";
54070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
54170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_RESP:
54270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Probe Response";
54370b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
54470b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            case IEEE_80211_FRAME_CTRL_SUBTYPE_AUTH:
54570b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Authentication";
5465e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                parseAuthenticationFrame(data);
54770b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
54870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan            default:
54970b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                mTypeString = "Unexpected subtype " + ieee80211FrameSubtype;
55070b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan                return;
55170b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan        }
55270b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan    }
5535e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5545e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    // Per 802.11-2012 Secs 8.3.3.6 and 8.4.1.
5555e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final byte IEEE_80211_CAPABILITY_INFO_LEN = 2;
5565e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private void parseAssociationResponse(ByteBuffer data) {
5575e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        data.position(data.position() + IEEE_80211_CAPABILITY_INFO_LEN);
5585e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        short resultCode = data.getShort();
5595e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        mResultString = String.format(
5605e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                "%d: %s", resultCode, decodeIeee80211StatusCode(resultCode));
5615e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    }
5625e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5635e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    // Per 802.11-2012 Secs 8.3.3.11 and 8.4.1.
5645e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final short IEEE_80211_AUTH_ALG_OPEN = 0;
5655e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final short IEEE_80211_AUTH_ALG_SHARED_KEY = 1;
5665e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final short IEEE_80211_AUTH_ALG_FAST_BSS_TRANSITION = 2;
5675e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private static final short IEEE_80211_AUTH_ALG_SIMUL_AUTH_OF_EQUALS = 3;
5685e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private void parseAuthenticationFrame(ByteBuffer data) {
5695e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        short algorithm = data.getShort();
5705e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        short sequenceNum = data.getShort();
5715e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        boolean hasResultCode = false;
5725e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        switch (algorithm) {
5735e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case IEEE_80211_AUTH_ALG_OPEN:
5745e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case IEEE_80211_AUTH_ALG_SHARED_KEY:
5755e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                if (sequenceNum == 2) {
5765e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                    hasResultCode = true;
5775e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                }
5785e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                break;
5795e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case IEEE_80211_AUTH_ALG_FAST_BSS_TRANSITION:
5805e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                if (sequenceNum == 2 || sequenceNum == 4) {
5815e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                    hasResultCode = true;
5825e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                }
5835e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                break;
5845e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case IEEE_80211_AUTH_ALG_SIMUL_AUTH_OF_EQUALS:
5855e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                hasResultCode = true;
5865e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                break;
5875e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            default:
5885e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                // Ignore unknown algorithm -- don't know which frames would have result codes.
5895e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        }
5905e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5915e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        if (hasResultCode) {
5925e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            short resultCode = data.getShort();
5935e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            mResultString = String.format(
5945e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                    "%d: %s", resultCode, decodeIeee80211StatusCode(resultCode));
5955e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        }
5965e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    }
5975e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal
5985e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    // Per 802.11-2012 Table 8-37.
5995e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    private String decodeIeee80211StatusCode(short statusCode) {
6005e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        switch (statusCode) {
6015e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 0:
6025e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Success";
6035e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 1:
6045e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unspecified failure";
6055e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 2:
6065e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TDLS wakeup schedule rejected; alternative provided";
6075e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 3:
6085e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TDLS wakeup schedule rejected";
6095e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 4:
6105e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
6115e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 5:
6125e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Security disabled";
6135e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 6:
6145e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unacceptable lifetime";
6155e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 7:
6165e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Not in same BSS";
6175e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 8:
6185e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 9:
6195e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
6205e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 10:
6215e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Capabilities mismatch";
6225e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 11:
6235e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reassociation denied; could not confirm association exists";
6245e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 12:
6255e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied for reasons outside standard";
6265e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 13:
6275e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unsupported authentication algorithm";
6285e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 14:
6295e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Authentication sequence number of of sequence";
6305e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 15:
6315e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Authentication challenge failure";
6325e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 16:
6335e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Authentication timeout";
6345e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 17:
6355e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; too many STAs";
6365e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 18:
6375e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support BSSBasicRateSet";
6385e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 19:
6395e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support short preamble";
6405e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 20:
6415e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support PBCC";
6425e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 21:
6435e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support channel agility";
6445e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 22:
6455e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association rejected; must support spectrum management";
6465e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 23:
6475e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association rejected; unacceptable power capability";
6485e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 24:
6495e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association rejected; unacceptable supported channels";
6505e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 25:
6515e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support short slot time";
6525e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 26:
6535e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support DSSS-OFDM";
6545e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 27:
6555e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support HT";
6565e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 28:
6575e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "R0 keyholder unreachable (802.11r)";
6585e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 29:
6595e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support PCO transition time";
6605e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 30:
6615e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Refused temporarily";
6625e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 31:
6635e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Robust management frame policy violation";
6645e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 32:
6655e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unspecified QoS failure";
6665e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 33:
6675e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; insufficient bandwidth for QoS";
6685e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 34:
6695e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; poor channel";
6705e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 35:
6715e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; must support QoS";
6725e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 36:
6735e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
6745e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 37:
6755e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Declined";
6765e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 38:
6775e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid parameters";
6785e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 39:
6795e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TS cannot be honored; changes suggested";
6805e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 40:
6815e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid element";
6825e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 41:
6835e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid group cipher";
6845e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 42:
6855e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid pairwise cipher";
6865e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 43:
6875e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid auth/key mgmt proto (AKMP)";
6885e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 44:
6895e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unsupported RSNE version";
6905e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 45:
6915e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid RSNE capabilities";
6925e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 46:
6935e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Cipher suite rejected by policy";
6945e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 47:
6955e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TS cannot be honored now; try again later";
6965e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 48:
6975e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Direct link rejected by policy";
6985e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 49:
6995e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Destination STA not in BSS";
7005e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 50:
7015e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Destination STA not configured for QoS";
7025e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 51:
7035e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Association denied; listen interval too large";
7045e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 52:
7055e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid fast transition action frame count";
7065e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 53:
7075e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid PMKID";
7085e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 54:
7095e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid MDE";
7105e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 55:
7115e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid FTE";
7125e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 56:
7135e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Unsupported TCLAS";
7145e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 57:
7155e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Requested TCLAS exceeds resources";
7165e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 58:
7175e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TS cannot be honored; try another BSS";
7185e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 59:
7195e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "GAS Advertisement not supported";
7205e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 60:
7215e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "No outstanding GAS request";
7225e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 61:
7235e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "No query response from GAS server";
7245e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 62:
7255e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "GAS query timeout";
7265e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 63:
7275e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "GAS response too large";
7285e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 64:
7295e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Home network does not support request";
7305e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 65:
7315e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Advertisement server unreachable";
7325e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 66:
7335e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
7345e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 67:
7355e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Rejected for SSP permissions";
7365e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 68:
7375e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Authentication required";
7385e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 69:
7395e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 70:
7405e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 71:
7415e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
7425e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 72:
7435e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Invalid RSNE contents";
7445e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 73:
7455e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "U-APSD coexistence unsupported";
7465e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 74:
7475e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Requested U-APSD coex mode unsupported";
7485e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 75:
7495e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Requested parameter unsupported with U-APSD coex";
7505e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 76:
7515e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Auth rejected; anti-clogging token required";
7525e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 77:
7535e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Auth rejected; offered group is not supported";
7545e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 78:
7555e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Cannot find alternative TBTT";
7565e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 79:
7575e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Transmission failure";
7585e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 80:
7595e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Requested TCLAS not supported";
7605e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 81:
7615e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "TCLAS resources exhausted";
7625e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 82:
7635e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Rejected with suggested BSS transition";
7645e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 83:
7655e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
7665e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 84:
7675e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 85:
7685e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 86:
7695e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 87:
7705e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 88:
7715e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 89:
7725e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 90:
7735e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 91:
7745e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "<unspecified>";
7755e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 92:
7765e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Refused due to external reason";
7775e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 93:
7785e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Refused; AP out of memory";
7795e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 94:
7805e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Refused; emergency services not supported";
7815e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 95:
7825e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "GAS query response outstanding";
7835e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 96:
7845e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 97:
7855e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 98:
7865e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 99:
7875e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
7885e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 100:
7895e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Failed; reservation conflict";
7905e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 101:
7915e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Failed; exceeded MAF limit";
7925e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            case 102:
7935e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Failed; exceeded MCCA track limit";
7945e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal            default:
7955e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal                return "Reserved";
7965e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal        }
7975e550bdccf8aaace892366fbbaf90bd0a7c456afmukesh agrawal    }
79870b4f7f1b8f57c5ae449dedb48edc0d07b6b5c41Samuel Tan}
799