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      */
FrameParser(byte frameType, byte[] frameBytes)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      */
getUnsignedByte(ByteBuffer data)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      */
getUnsignedShort(ByteBuffer data)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 
parseEthernetFrame(ByteBuffer data)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 
parseIpv4Packet(ByteBuffer data)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 
parseTcpPacket(ByteBuffer data)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 
parseUdpPacket(ByteBuffer data)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 
parseDhcpPacket(ByteBuffer data)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 
decodeDhcpMessageType(short messageType)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 
parseIcmpPacket(ByteBuffer data)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 
parseArpPacket(ByteBuffer data)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 
parseIpv6Packet(ByteBuffer data)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 
parseIcmpV6Packet(ByteBuffer data)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 
parseEapolPacket(ByteBuffer data)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 
parseIeee80211FrameCtrlVersion(byte b)493     private static byte parseIeee80211FrameCtrlVersion(byte b) {
494         return (byte) (b & 0b00000011);
495     }
parseIeee80211FrameCtrlType(byte b)496     private static byte parseIeee80211FrameCtrlType(byte b) {
497         return (byte) ((b & 0b00001100) >> 2);
498     }
parseIeee80211FrameCtrlSubtype(byte b)499     private static byte parseIeee80211FrameCtrlSubtype(byte b) {
500         return (byte) ((b & 0b11110000) >> 4);
501     }
parseManagementFrame(ByteBuffer data)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;
parseAssociationResponse(ByteBuffer data)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;
parseAuthenticationFrame(ByteBuffer data)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.
decodeIeee80211StatusCode(short statusCode)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