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 */
16package com.android.server.wifi.util;
17
18import android.util.Log;
19
20import com.android.server.wifi.WifiLoggerHal;
21
22import java.nio.BufferUnderflowException;
23import java.nio.ByteBuffer;
24import java.nio.ByteOrder;
25import java.util.HashSet;
26import 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 */
32public 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