Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.server.wifi.util;
     17 
     18 import android.util.Log;
     19 
     20 import com.android.server.wifi.WifiLoggerHal;
     21 
     22 import java.nio.BufferUnderflowException;
     23 import java.nio.ByteBuffer;
     24 import java.nio.ByteOrder;
     25 import java.util.HashSet;
     26 import java.util.Set;
     27 
     28 /**
     29  * This class parses the raw bytes of a network frame, and stores the parsed information in its
     30  * public fields.
     31  */
     32 public class FrameParser {
     33     /**
     34      * Note: When adding constants derived from network protocol specifications, please encode
     35      * these constants the same way as the relevant specification, for ease of comparison.
     36      */
     37 
     38     private static final String TAG = "FrameParser";
     39 
     40     /* These fields hold the information parsed from this frame. */
     41     public String mMostSpecificProtocolString = "N/A";
     42     public String mTypeString = "N/A";
     43     public String mResultString = "N/A";
     44 
     45     /**
     46      * Parses the contents of a given network frame.
     47      *
     48      * @param frameType The type of the frame, as defined in
     49      * {@link com.android.server.wifi.WifiLoggerHal}.
     50      * @param frameBytes The raw bytes of the frame to be parsed.
     51      */
     52     public FrameParser(byte frameType, byte[] frameBytes) {
     53         try {
     54             ByteBuffer frameBuffer = ByteBuffer.wrap(frameBytes);
     55             frameBuffer.order(ByteOrder.BIG_ENDIAN);
     56             if (frameType == WifiLoggerHal.FRAME_TYPE_ETHERNET_II) {
     57                 parseEthernetFrame(frameBuffer);
     58             } else if (frameType == WifiLoggerHal.FRAME_TYPE_80211_MGMT) {
     59                 parseManagementFrame(frameBuffer);
     60             }
     61         } catch (BufferUnderflowException | IllegalArgumentException e) {
     62             Log.e(TAG, "Dissection aborted mid-frame: " + e);
     63         }
     64     }
     65 
     66     /**
     67      * Read one byte into a form that can easily be compared against, or output as, an integer
     68      * in the range (0, 255).
     69      */
     70     private static short getUnsignedByte(ByteBuffer data) {
     71         return (short) (data.get() & 0x00ff);
     72     }
     73     /**
     74      * Read two bytes into a form that can easily be compared against, or output as, an integer
     75      * in the range (0, 65535).
     76      */
     77     private static int getUnsignedShort(ByteBuffer data) {
     78         return (data.getShort() & 0xffff);
     79     }
     80 
     81     private static final int ETHERNET_SRC_MAC_ADDR_LEN = 6;
     82     private static final int ETHERNET_DST_MAC_ADDR_LEN = 6;
     83     private static final short ETHERTYPE_IP_V4 = (short) 0x0800;
     84     private static final short ETHERTYPE_ARP = (short) 0x0806;
     85     private static final short ETHERTYPE_IP_V6 = (short) 0x86dd;
     86     private static final short ETHERTYPE_EAPOL = (short) 0x888e;
     87 
     88     private void parseEthernetFrame(ByteBuffer data) {
     89         mMostSpecificProtocolString = "Ethernet";
     90         data.position(data.position() + ETHERNET_SRC_MAC_ADDR_LEN + ETHERNET_DST_MAC_ADDR_LEN);
     91         short etherType = data.getShort();
     92         switch (etherType) {
     93             case ETHERTYPE_IP_V4:
     94                 parseIpv4Packet(data);
     95                 return;
     96             case ETHERTYPE_ARP:
     97                 parseArpPacket(data);
     98                 return;
     99             case ETHERTYPE_IP_V6:
    100                 parseIpv6Packet(data);
    101                 return;
    102             case ETHERTYPE_EAPOL:
    103                 parseEapolPacket(data);
    104                 return;
    105             default:
    106                 return;
    107         }
    108     }
    109 
    110     private static final byte IP_V4_VERSION_BYTE_MASK = (byte) 0b11110000;
    111     private static final byte IP_V4_IHL_BYTE_MASK = (byte) 0b00001111;
    112     private static final byte IP_V4_ADDR_LEN = 4;
    113     private static final byte IP_V4_DSCP_AND_ECN_LEN = 1;
    114     private static final byte IP_V4_TOTAL_LEN_LEN = 2;
    115     private static final byte IP_V4_ID_LEN = 2;
    116     private static final byte IP_V4_FLAGS_AND_FRAG_OFFSET_LEN = 2;
    117     private static final byte IP_V4_TTL_LEN = 1;
    118     private static final byte IP_V4_HEADER_CHECKSUM_LEN = 2;
    119     private static final byte IP_V4_SRC_ADDR_LEN = 4;
    120     private static final byte IP_V4_DST_ADDR_LEN = 4;
    121     private static final byte IP_PROTO_ICMP = 1;
    122     private static final byte IP_PROTO_TCP = 6;
    123     private static final byte IP_PROTO_UDP = 17;
    124     private static final byte BYTES_PER_QUAD = 4;
    125 
    126     private void parseIpv4Packet(ByteBuffer data) {
    127         mMostSpecificProtocolString = "IPv4";
    128         data.mark();
    129         byte versionAndHeaderLen = data.get();
    130         int version = (versionAndHeaderLen & IP_V4_VERSION_BYTE_MASK) >> 4;
    131         if (version != 4) {
    132             Log.e(TAG, "IPv4 header: Unrecognized protocol version " + version);
    133             return;
    134         }
    135 
    136         data.position(data.position() + IP_V4_DSCP_AND_ECN_LEN + IP_V4_TOTAL_LEN_LEN
    137                 + IP_V4_ID_LEN + IP_V4_FLAGS_AND_FRAG_OFFSET_LEN + IP_V4_TTL_LEN);
    138         short protocolNumber = getUnsignedByte(data);
    139         data.position(data.position() + IP_V4_HEADER_CHECKSUM_LEN + IP_V4_SRC_ADDR_LEN
    140                 + IP_V4_DST_ADDR_LEN);
    141 
    142         int headerLen = (versionAndHeaderLen & IP_V4_IHL_BYTE_MASK) * BYTES_PER_QUAD;
    143         data.reset();  // back to start of IPv4 header
    144         data.position(data.position() + headerLen);
    145 
    146         switch (protocolNumber) {
    147             case IP_PROTO_ICMP:
    148                 parseIcmpPacket(data);
    149                 break;
    150             case IP_PROTO_TCP:
    151                 parseTcpPacket(data);
    152                 break;
    153             case IP_PROTO_UDP:
    154                 parseUdpPacket(data);
    155                 break;
    156             default:
    157                 break;
    158         }
    159     }
    160 
    161     private static final byte TCP_SRC_PORT_LEN = 2;
    162     private static final int HTTPS_PORT = 443;
    163     private static final Set<Integer> HTTP_PORTS = new HashSet<>();
    164     static {
    165         HTTP_PORTS.add(80);
    166         HTTP_PORTS.add(3128);
    167         HTTP_PORTS.add(3132);
    168         HTTP_PORTS.add(5985);
    169         HTTP_PORTS.add(8080);
    170         HTTP_PORTS.add(8088);
    171         HTTP_PORTS.add(11371);
    172         HTTP_PORTS.add(1900);
    173         HTTP_PORTS.add(2869);
    174         HTTP_PORTS.add(2710);
    175     }
    176 
    177     private void parseTcpPacket(ByteBuffer data) {
    178         mMostSpecificProtocolString = "TCP";
    179         data.position(data.position() + TCP_SRC_PORT_LEN);
    180         int dstPort = getUnsignedShort(data);
    181 
    182         if (dstPort == HTTPS_PORT) {
    183             mTypeString = "HTTPS";
    184         } else if (HTTP_PORTS.contains(dstPort)) {
    185             mTypeString = "HTTP";
    186         }
    187     }
    188 
    189     private static final byte UDP_PORT_BOOTPS = 67;
    190     private static final byte UDP_PORT_BOOTPC = 68;
    191     private static final byte UDP_PORT_NTP = 123;
    192     private static final byte UDP_CHECKSUM_LEN = 2;
    193 
    194     private void parseUdpPacket(ByteBuffer data) {
    195         mMostSpecificProtocolString = "UDP";
    196         int srcPort = getUnsignedShort(data);
    197         int dstPort = getUnsignedShort(data);
    198         int length = getUnsignedShort(data);
    199 
    200         data.position(data.position() + UDP_CHECKSUM_LEN);
    201         if ((srcPort == UDP_PORT_BOOTPC && dstPort == UDP_PORT_BOOTPS)
    202                 || (srcPort == UDP_PORT_BOOTPS && dstPort == UDP_PORT_BOOTPC)) {
    203             parseDhcpPacket(data);
    204             return;
    205         }
    206         if (srcPort == UDP_PORT_NTP || dstPort == UDP_PORT_NTP) {
    207             mMostSpecificProtocolString = "NTP";
    208             return;
    209         }
    210     }
    211 
    212     private static final byte BOOTP_OPCODE_LEN = 1;
    213     private static final byte BOOTP_HWTYPE_LEN = 1;
    214     private static final byte BOOTP_HWADDR_LEN_LEN = 1;
    215     private static final byte BOOTP_HOPCOUNT_LEN = 1;
    216     private static final byte BOOTP_TRANSACTION_ID_LEN = 4;
    217     private static final byte BOOTP_ELAPSED_SECONDS_LEN = 2;
    218     private static final byte BOOTP_FLAGS_LEN = 2;
    219     private static final byte BOOTP_CLIENT_HWADDR_LEN = 16;
    220     private static final byte BOOTP_SERVER_HOSTNAME_LEN = 64;
    221     private static final short BOOTP_BOOT_FILENAME_LEN = 128;
    222     private static final byte BOOTP_MAGIC_COOKIE_LEN = 4;
    223     private static final short DHCP_OPTION_TAG_PAD = 0;
    224     private static final short DHCP_OPTION_TAG_MESSAGE_TYPE = 53;
    225     private static final short DHCP_OPTION_TAG_END = 255;
    226 
    227     private void parseDhcpPacket(ByteBuffer data) {
    228         mMostSpecificProtocolString = "DHCP";
    229         data.position(data.position() + BOOTP_OPCODE_LEN + BOOTP_HWTYPE_LEN + BOOTP_HWADDR_LEN_LEN
    230                 + BOOTP_HOPCOUNT_LEN + BOOTP_TRANSACTION_ID_LEN + BOOTP_ELAPSED_SECONDS_LEN
    231                 + BOOTP_FLAGS_LEN + IP_V4_ADDR_LEN * 4 + BOOTP_CLIENT_HWADDR_LEN
    232                 + BOOTP_SERVER_HOSTNAME_LEN + BOOTP_BOOT_FILENAME_LEN + BOOTP_MAGIC_COOKIE_LEN);
    233         while (data.remaining() > 0) {
    234             short dhcpOptionTag = getUnsignedByte(data);
    235             if (dhcpOptionTag == DHCP_OPTION_TAG_PAD) {
    236                 continue;
    237             }
    238             if (dhcpOptionTag == DHCP_OPTION_TAG_END) {
    239                 break;
    240             }
    241             short dhcpOptionLen = getUnsignedByte(data);
    242             switch (dhcpOptionTag) {
    243                 case DHCP_OPTION_TAG_MESSAGE_TYPE:
    244                     if (dhcpOptionLen != 1) {
    245                         Log.e(TAG, "DHCP option len: " + dhcpOptionLen  + " (expected |1|)");
    246                         return;
    247                     }
    248                     mTypeString = decodeDhcpMessageType(getUnsignedByte(data));
    249                     return;
    250                 default:
    251                     data.position(data.position() + dhcpOptionLen);
    252             }
    253         }
    254     }
    255 
    256     private static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
    257     private static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
    258     private static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
    259     private static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
    260     private static final byte DHCP_MESSAGE_TYPE_ACK = 5;
    261     private static final byte DHCP_MESSAGE_TYPE_NAK = 6;
    262     private static final byte DHCP_MESSAGE_TYPE_RELEASE = 7;
    263     private static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
    264 
    265     private static String decodeDhcpMessageType(short messageType) {
    266         switch (messageType) {
    267             case DHCP_MESSAGE_TYPE_DISCOVER:
    268                 return "Discover";
    269             case DHCP_MESSAGE_TYPE_OFFER:
    270                 return "Offer";
    271             case DHCP_MESSAGE_TYPE_REQUEST:
    272                 return "Request";
    273             case DHCP_MESSAGE_TYPE_DECLINE:
    274                 return "Decline";
    275             case DHCP_MESSAGE_TYPE_ACK:
    276                 return "Ack";
    277             case DHCP_MESSAGE_TYPE_NAK:
    278                 return "Nak";
    279             case DHCP_MESSAGE_TYPE_RELEASE:
    280                 return "Release";
    281             case DHCP_MESSAGE_TYPE_INFORM:
    282                 return "Inform";
    283             default:
    284                 return "Unknown type " + messageType;
    285         }
    286     }
    287 
    288     private static final byte ICMP_TYPE_ECHO_REPLY = 0;
    289     private static final byte ICMP_TYPE_DEST_UNREACHABLE = 3;
    290     private static final byte ICMP_TYPE_REDIRECT = 5;
    291     private static final byte ICMP_TYPE_ECHO_REQUEST = 8;
    292 
    293     private void parseIcmpPacket(ByteBuffer data) {
    294         mMostSpecificProtocolString = "ICMP";
    295         short messageType = getUnsignedByte(data);
    296         switch (messageType) {
    297             case ICMP_TYPE_ECHO_REPLY:
    298                 mTypeString = "Echo Reply";
    299                 return;
    300             case ICMP_TYPE_DEST_UNREACHABLE:
    301                 mTypeString = "Destination Unreachable";
    302                 return;
    303             case ICMP_TYPE_REDIRECT:
    304                 mTypeString = "Redirect";
    305                 return;
    306             case ICMP_TYPE_ECHO_REQUEST:
    307                 mTypeString = "Echo Request";
    308                 return;
    309             default:
    310                 mTypeString = "Type " + messageType;
    311                 return;
    312         }
    313     }
    314 
    315     private static final byte ARP_HWTYPE_LEN = 2;
    316     private static final byte ARP_PROTOTYPE_LEN = 2;
    317     private static final byte ARP_HWADDR_LEN_LEN = 1;
    318     private static final byte ARP_PROTOADDR_LEN_LEN = 1;
    319     private static final byte ARP_OPCODE_REQUEST = 1;
    320     private static final byte ARP_OPCODE_REPLY = 2;
    321 
    322     private void parseArpPacket(ByteBuffer data) {
    323         mMostSpecificProtocolString = "ARP";
    324         data.position(data.position() + ARP_HWTYPE_LEN + ARP_PROTOTYPE_LEN + ARP_HWADDR_LEN_LEN
    325                 + ARP_PROTOADDR_LEN_LEN);
    326         int opCode = getUnsignedShort(data);
    327         switch (opCode) {
    328             case ARP_OPCODE_REQUEST:
    329                 mTypeString = "Request";
    330                 break;
    331             case ARP_OPCODE_REPLY:
    332                 mTypeString = "Reply";
    333                 break;
    334             default:
    335                 mTypeString = "Operation " + opCode;
    336         }
    337     }
    338 
    339     private static final byte IP_V6_PAYLOAD_LENGTH_LEN = 2;
    340     private static final byte IP_V6_HOP_LIMIT_LEN = 1;
    341     private static final byte IP_V6_ADDR_LEN = 16;
    342     private static final byte IP_V6_HEADER_TYPE_HOP_BY_HOP_OPTION = 0;
    343     private static final byte IP_V6_HEADER_TYPE_ICMP_V6 = 58;
    344     private static final byte BYTES_PER_OCT = 8;
    345 
    346     private void parseIpv6Packet(ByteBuffer data) {
    347         mMostSpecificProtocolString = "IPv6";
    348         int versionClassAndLabel = data.getInt();
    349         int version = (versionClassAndLabel & 0xf0000000) >> 28;
    350         if (version != 6) {
    351             Log.e(TAG, "IPv6 header: invalid IP version " + version);
    352             return;
    353         }
    354         data.position(data.position() + IP_V6_PAYLOAD_LENGTH_LEN);
    355 
    356         short nextHeaderType = getUnsignedByte(data);
    357         data.position(data.position() + IP_V6_HOP_LIMIT_LEN + IP_V6_ADDR_LEN * 2);
    358         while (nextHeaderType == IP_V6_HEADER_TYPE_HOP_BY_HOP_OPTION) {
    359             int thisHeaderLen;
    360             data.mark();
    361             nextHeaderType = getUnsignedByte(data);
    362             thisHeaderLen = (getUnsignedByte(data) + 1) * BYTES_PER_OCT;
    363             data.reset();  // back to start of this header
    364             data.position(data.position() + thisHeaderLen);
    365         }
    366         switch (nextHeaderType) {
    367             case IP_V6_HEADER_TYPE_ICMP_V6:
    368                 parseIcmpV6Packet(data);
    369                 return;
    370             default:
    371                 mTypeString = "Option/Protocol " + nextHeaderType;
    372                 return;
    373         }
    374     }
    375 
    376     private static final short ICMP_V6_TYPE_ECHO_REQUEST = 128;
    377     private static final short ICMP_V6_TYPE_ECHO_REPLY = 129;
    378     private static final short ICMP_V6_TYPE_ROUTER_SOLICITATION = 133;
    379     private static final short ICMP_V6_TYPE_ROUTER_ADVERTISEMENT = 134;
    380     private static final short ICMP_V6_TYPE_NEIGHBOR_SOLICITATION = 135;
    381     private static final short ICMP_V6_TYPE_NEIGHBOR_ADVERTISEMENT = 136;
    382     private static final short ICMP_V6_TYPE_MULTICAST_LISTENER_DISCOVERY = 143;
    383 
    384     private void parseIcmpV6Packet(ByteBuffer data) {
    385         mMostSpecificProtocolString = "ICMPv6";
    386         short icmpV6Type = getUnsignedByte(data);
    387         switch (icmpV6Type) {
    388             case ICMP_V6_TYPE_ECHO_REQUEST:
    389                 mTypeString = "Echo Request";
    390                 return;
    391             case ICMP_V6_TYPE_ECHO_REPLY:
    392                 mTypeString = "Echo Reply";
    393                 return;
    394             case ICMP_V6_TYPE_ROUTER_SOLICITATION:
    395                 mTypeString = "Router Solicitation";
    396                 return;
    397             case ICMP_V6_TYPE_ROUTER_ADVERTISEMENT:
    398                 mTypeString = "Router Advertisement";
    399                 return;
    400             case ICMP_V6_TYPE_NEIGHBOR_SOLICITATION:
    401                 mTypeString = "Neighbor Solicitation";
    402                 return;
    403             case ICMP_V6_TYPE_NEIGHBOR_ADVERTISEMENT:
    404                 mTypeString = "Neighbor Advertisement";
    405                 return;
    406             case ICMP_V6_TYPE_MULTICAST_LISTENER_DISCOVERY:
    407                 mTypeString = "MLDv2 report";
    408                 return;
    409             default:
    410                 mTypeString = "Type " + icmpV6Type;
    411                 return;
    412         }
    413     }
    414 
    415     private static final byte EAPOL_TYPE_KEY = 3;
    416     private static final byte EAPOL_KEY_DESCRIPTOR_RSN_KEY = 2;
    417     private static final byte EAPOL_LENGTH_LEN = 2;
    418     private static final short WPA_KEY_INFO_FLAG_PAIRWISE = (short) 1 << 3;  // bit 4
    419     private static final short WPA_KEY_INFO_FLAG_INSTALL = (short) 1 << 6;  // bit 7
    420     private static final short WPA_KEY_INFO_FLAG_MIC = (short) 1 << 8;  // bit 9
    421     private static final byte WPA_KEYLEN_LEN = 2;
    422     private static final byte WPA_REPLAY_COUNTER_LEN = 8;
    423     private static final byte WPA_KEY_NONCE_LEN = 32;
    424     private static final byte WPA_KEY_IV_LEN = 16;
    425     private static final byte WPA_KEY_RECEIVE_SEQUENCE_COUNTER_LEN = 8;
    426     private static final byte WPA_KEY_IDENTIFIER_LEN = 8;
    427     private static final byte WPA_KEY_MIC_LEN = 16;
    428 
    429     private void parseEapolPacket(ByteBuffer data) {
    430         mMostSpecificProtocolString = "EAPOL";
    431         short eapolVersion = getUnsignedByte(data);
    432         if (eapolVersion < 1 || eapolVersion > 2) {
    433             Log.e(TAG, "Unrecognized EAPOL version " + eapolVersion);
    434             return;
    435         }
    436 
    437         short eapolType = getUnsignedByte(data);
    438         if (eapolType != EAPOL_TYPE_KEY) {
    439             Log.e(TAG, "Unrecognized EAPOL type " + eapolType);
    440             return;
    441         }
    442 
    443         data.position(data.position() + EAPOL_LENGTH_LEN);
    444         short eapolKeyDescriptorType = getUnsignedByte(data);
    445         if (eapolKeyDescriptorType != EAPOL_KEY_DESCRIPTOR_RSN_KEY) {
    446             Log.e(TAG, "Unrecognized key descriptor " + eapolKeyDescriptorType);
    447             return;
    448         }
    449 
    450         short wpaKeyInfo = data.getShort();
    451         if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_PAIRWISE) == 0) {
    452             mTypeString = "Group Key";
    453         } else {
    454             mTypeString = "Pairwise Key";
    455         }
    456 
    457         // See goo.gl/tu8AQC for details.
    458         if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_MIC) == 0) {
    459             mTypeString += " message 1/4";
    460             return;
    461         }
    462 
    463         if ((wpaKeyInfo & WPA_KEY_INFO_FLAG_INSTALL) != 0) {
    464             mTypeString += " message 3/4";
    465             return;
    466         }
    467 
    468         data.position(data.position() + WPA_KEYLEN_LEN + WPA_REPLAY_COUNTER_LEN
    469                 + WPA_KEY_NONCE_LEN + WPA_KEY_IV_LEN + WPA_KEY_RECEIVE_SEQUENCE_COUNTER_LEN
    470                 + WPA_KEY_IDENTIFIER_LEN + WPA_KEY_MIC_LEN);
    471         int wpaKeyDataLen = getUnsignedShort(data);
    472         if (wpaKeyDataLen > 0) {
    473             mTypeString += " message 2/4";
    474         } else {
    475             mTypeString += " message 4/4";
    476         }
    477     }
    478 
    479     private static final byte IEEE_80211_FRAME_CTRL_TYPE_MGMT = 0x00;
    480     private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_REQ = 0x00;
    481     private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_RESP = 0x01;
    482     private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_REQ = 0x04;
    483     private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_RESP = 0x05;
    484     private static final byte IEEE_80211_FRAME_CTRL_SUBTYPE_AUTH = 0x0b;
    485     private static final byte IEEE_80211_FRAME_CTRL_FLAG_ORDER = (byte) (1 << 7); // bit 8
    486     private static final byte IEEE_80211_DURATION_LEN = 2;
    487     private static final byte IEEE_80211_ADDR1_LEN = 6;
    488     private static final byte IEEE_80211_ADDR2_LEN = 6;
    489     private static final byte IEEE_80211_ADDR3_LEN = 6;
    490     private static final byte IEEE_80211_SEQUENCE_CONTROL_LEN = 2;
    491     private static final byte IEEE_80211_HT_CONTROL_LEN = 4;
    492 
    493     private static byte parseIeee80211FrameCtrlVersion(byte b) {
    494         return (byte) (b & 0b00000011);
    495     }
    496     private static byte parseIeee80211FrameCtrlType(byte b) {
    497         return (byte) ((b & 0b00001100) >> 2);
    498     }
    499     private static byte parseIeee80211FrameCtrlSubtype(byte b) {
    500         return (byte) ((b & 0b11110000) >> 4);
    501     }
    502     private void parseManagementFrame(ByteBuffer data) {  // 802.11-2012 Sec 8.3.3.1
    503         data.order(ByteOrder.LITTLE_ENDIAN);
    504 
    505         mMostSpecificProtocolString = "802.11 Mgmt";
    506         byte frameControlVersionTypeSubtype = data.get();
    507         byte ieee80211Version = parseIeee80211FrameCtrlVersion(frameControlVersionTypeSubtype);
    508         if (ieee80211Version != 0) {
    509             Log.e(TAG, "Unrecognized 802.11 version " + ieee80211Version);
    510             return;
    511         }
    512 
    513         byte ieee80211FrameType = parseIeee80211FrameCtrlType(frameControlVersionTypeSubtype);
    514         if (ieee80211FrameType != IEEE_80211_FRAME_CTRL_TYPE_MGMT) {
    515             Log.e(TAG, "Unexpected frame type " + ieee80211FrameType);
    516             return;
    517         }
    518 
    519         byte frameControlFlags = data.get();
    520 
    521         data.position(data.position() + IEEE_80211_DURATION_LEN + IEEE_80211_ADDR1_LEN
    522                 + IEEE_80211_ADDR2_LEN + IEEE_80211_ADDR3_LEN + IEEE_80211_SEQUENCE_CONTROL_LEN);
    523 
    524         if ((frameControlFlags & IEEE_80211_FRAME_CTRL_FLAG_ORDER) != 0) {
    525             // Per 802.11-2012 Sec 8.2.4.1.10.
    526             data.position(data.position() + IEEE_80211_HT_CONTROL_LEN);
    527         }
    528 
    529         byte ieee80211FrameSubtype = parseIeee80211FrameCtrlSubtype(frameControlVersionTypeSubtype);
    530         switch (ieee80211FrameSubtype) {
    531             case IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_REQ:
    532                 mTypeString = "Association Request";
    533                 return;
    534             case IEEE_80211_FRAME_CTRL_SUBTYPE_ASSOC_RESP:
    535                 mTypeString = "Association Response";
    536                 parseAssociationResponse(data);
    537                 return;
    538             case IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_REQ:
    539                 mTypeString = "Probe Request";
    540                 return;
    541             case IEEE_80211_FRAME_CTRL_SUBTYPE_PROBE_RESP:
    542                 mTypeString = "Probe Response";
    543                 return;
    544             case IEEE_80211_FRAME_CTRL_SUBTYPE_AUTH:
    545                 mTypeString = "Authentication";
    546                 parseAuthenticationFrame(data);
    547                 return;
    548             default:
    549                 mTypeString = "Unexpected subtype " + ieee80211FrameSubtype;
    550                 return;
    551         }
    552     }
    553 
    554     // Per 802.11-2012 Secs 8.3.3.6 and 8.4.1.
    555     private static final byte IEEE_80211_CAPABILITY_INFO_LEN = 2;
    556     private void parseAssociationResponse(ByteBuffer data) {
    557         data.position(data.position() + IEEE_80211_CAPABILITY_INFO_LEN);
    558         short resultCode = data.getShort();
    559         mResultString = String.format(
    560                 "%d: %s", resultCode, decodeIeee80211StatusCode(resultCode));
    561     }
    562 
    563     // Per 802.11-2012 Secs 8.3.3.11 and 8.4.1.
    564     private static final short IEEE_80211_AUTH_ALG_OPEN = 0;
    565     private static final short IEEE_80211_AUTH_ALG_SHARED_KEY = 1;
    566     private static final short IEEE_80211_AUTH_ALG_FAST_BSS_TRANSITION = 2;
    567     private static final short IEEE_80211_AUTH_ALG_SIMUL_AUTH_OF_EQUALS = 3;
    568     private void parseAuthenticationFrame(ByteBuffer data) {
    569         short algorithm = data.getShort();
    570         short sequenceNum = data.getShort();
    571         boolean hasResultCode = false;
    572         switch (algorithm) {
    573             case IEEE_80211_AUTH_ALG_OPEN:
    574             case IEEE_80211_AUTH_ALG_SHARED_KEY:
    575                 if (sequenceNum == 2) {
    576                     hasResultCode = true;
    577                 }
    578                 break;
    579             case IEEE_80211_AUTH_ALG_FAST_BSS_TRANSITION:
    580                 if (sequenceNum == 2 || sequenceNum == 4) {
    581                     hasResultCode = true;
    582                 }
    583                 break;
    584             case IEEE_80211_AUTH_ALG_SIMUL_AUTH_OF_EQUALS:
    585                 hasResultCode = true;
    586                 break;
    587             default:
    588                 // Ignore unknown algorithm -- don't know which frames would have result codes.
    589         }
    590 
    591         if (hasResultCode) {
    592             short resultCode = data.getShort();
    593             mResultString = String.format(
    594                     "%d: %s", resultCode, decodeIeee80211StatusCode(resultCode));
    595         }
    596     }
    597 
    598     // Per 802.11-2012 Table 8-37.
    599     private String decodeIeee80211StatusCode(short statusCode) {
    600         switch (statusCode) {
    601             case 0:
    602                 return "Success";
    603             case 1:
    604                 return "Unspecified failure";
    605             case 2:
    606                 return "TDLS wakeup schedule rejected; alternative provided";
    607             case 3:
    608                 return "TDLS wakeup schedule rejected";
    609             case 4:
    610                 return "Reserved";
    611             case 5:
    612                 return "Security disabled";
    613             case 6:
    614                 return "Unacceptable lifetime";
    615             case 7:
    616                 return "Not in same BSS";
    617             case 8:
    618             case 9:
    619                 return "Reserved";
    620             case 10:
    621                 return "Capabilities mismatch";
    622             case 11:
    623                 return "Reassociation denied; could not confirm association exists";
    624             case 12:
    625                 return "Association denied for reasons outside standard";
    626             case 13:
    627                 return "Unsupported authentication algorithm";
    628             case 14:
    629                 return "Authentication sequence number of of sequence";
    630             case 15:
    631                 return "Authentication challenge failure";
    632             case 16:
    633                 return "Authentication timeout";
    634             case 17:
    635                 return "Association denied; too many STAs";
    636             case 18:
    637                 return "Association denied; must support BSSBasicRateSet";
    638             case 19:
    639                 return "Association denied; must support short preamble";
    640             case 20:
    641                 return "Association denied; must support PBCC";
    642             case 21:
    643                 return "Association denied; must support channel agility";
    644             case 22:
    645                 return "Association rejected; must support spectrum management";
    646             case 23:
    647                 return "Association rejected; unacceptable power capability";
    648             case 24:
    649                 return "Association rejected; unacceptable supported channels";
    650             case 25:
    651                 return "Association denied; must support short slot time";
    652             case 26:
    653                 return "Association denied; must support DSSS-OFDM";
    654             case 27:
    655                 return "Association denied; must support HT";
    656             case 28:
    657                 return "R0 keyholder unreachable (802.11r)";
    658             case 29:
    659                 return "Association denied; must support PCO transition time";
    660             case 30:
    661                 return "Refused temporarily";
    662             case 31:
    663                 return "Robust management frame policy violation";
    664             case 32:
    665                 return "Unspecified QoS failure";
    666             case 33:
    667                 return "Association denied; insufficient bandwidth for QoS";
    668             case 34:
    669                 return "Association denied; poor channel";
    670             case 35:
    671                 return "Association denied; must support QoS";
    672             case 36:
    673                 return "Reserved";
    674             case 37:
    675                 return "Declined";
    676             case 38:
    677                 return "Invalid parameters";
    678             case 39:
    679                 return "TS cannot be honored; changes suggested";
    680             case 40:
    681                 return "Invalid element";
    682             case 41:
    683                 return "Invalid group cipher";
    684             case 42:
    685                 return "Invalid pairwise cipher";
    686             case 43:
    687                 return "Invalid auth/key mgmt proto (AKMP)";
    688             case 44:
    689                 return "Unsupported RSNE version";
    690             case 45:
    691                 return "Invalid RSNE capabilities";
    692             case 46:
    693                 return "Cipher suite rejected by policy";
    694             case 47:
    695                 return "TS cannot be honored now; try again later";
    696             case 48:
    697                 return "Direct link rejected by policy";
    698             case 49:
    699                 return "Destination STA not in BSS";
    700             case 50:
    701                 return "Destination STA not configured for QoS";
    702             case 51:
    703                 return "Association denied; listen interval too large";
    704             case 52:
    705                 return "Invalid fast transition action frame count";
    706             case 53:
    707                 return "Invalid PMKID";
    708             case 54:
    709                 return "Invalid MDE";
    710             case 55:
    711                 return "Invalid FTE";
    712             case 56:
    713                 return "Unsupported TCLAS";
    714             case 57:
    715                 return "Requested TCLAS exceeds resources";
    716             case 58:
    717                 return "TS cannot be honored; try another BSS";
    718             case 59:
    719                 return "GAS Advertisement not supported";
    720             case 60:
    721                 return "No outstanding GAS request";
    722             case 61:
    723                 return "No query response from GAS server";
    724             case 62:
    725                 return "GAS query timeout";
    726             case 63:
    727                 return "GAS response too large";
    728             case 64:
    729                 return "Home network does not support request";
    730             case 65:
    731                 return "Advertisement server unreachable";
    732             case 66:
    733                 return "Reserved";
    734             case 67:
    735                 return "Rejected for SSP permissions";
    736             case 68:
    737                 return "Authentication required";
    738             case 69:
    739             case 70:
    740             case 71:
    741                 return "Reserved";
    742             case 72:
    743                 return "Invalid RSNE contents";
    744             case 73:
    745                 return "U-APSD coexistence unsupported";
    746             case 74:
    747                 return "Requested U-APSD coex mode unsupported";
    748             case 75:
    749                 return "Requested parameter unsupported with U-APSD coex";
    750             case 76:
    751                 return "Auth rejected; anti-clogging token required";
    752             case 77:
    753                 return "Auth rejected; offered group is not supported";
    754             case 78:
    755                 return "Cannot find alternative TBTT";
    756             case 79:
    757                 return "Transmission failure";
    758             case 80:
    759                 return "Requested TCLAS not supported";
    760             case 81:
    761                 return "TCLAS resources exhausted";
    762             case 82:
    763                 return "Rejected with suggested BSS transition";
    764             case 83:
    765                 return "Reserved";
    766             case 84:
    767             case 85:
    768             case 86:
    769             case 87:
    770             case 88:
    771             case 89:
    772             case 90:
    773             case 91:
    774                 return "<unspecified>";
    775             case 92:
    776                 return "Refused due to external reason";
    777             case 93:
    778                 return "Refused; AP out of memory";
    779             case 94:
    780                 return "Refused; emergency services not supported";
    781             case 95:
    782                 return "GAS query response outstanding";
    783             case 96:
    784             case 97:
    785             case 98:
    786             case 99:
    787                 return "Reserved";
    788             case 100:
    789                 return "Failed; reservation conflict";
    790             case 101:
    791                 return "Failed; exceeded MAF limit";
    792             case 102:
    793                 return "Failed; exceeded MCCA track limit";
    794             default:
    795                 return "Reserved";
    796         }
    797     }
    798 }
    799