Home | History | Annotate | Download | only in anqp
      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 
     17 package com.android.server.wifi.hotspot2.anqp;
     18 
     19 import com.android.internal.annotations.VisibleForTesting;
     20 import com.android.server.wifi.ByteBufferReader;
     21 
     22 import java.net.ProtocolException;
     23 import java.nio.BufferUnderflowException;
     24 import java.nio.ByteBuffer;
     25 import java.nio.ByteOrder;
     26 
     27 /**
     28  * Factory to build a collection of 802.11u ANQP elements from a byte buffer.
     29  */
     30 public class ANQPParser {
     31     /**
     32      * The OI value for Hotspot 2.0 ANQP-element.
     33      */
     34     @VisibleForTesting
     35     public static final int VENDOR_SPECIFIC_HS20_OI = 0x506F9A;
     36 
     37     /**
     38      * The Type value for Hotspot 2.0 ANQP-element.
     39      */
     40     @VisibleForTesting
     41     public static final int VENDOR_SPECIFIC_HS20_TYPE = 0x11;
     42 
     43     /**
     44      * Parse an ANQP element from the pass-in byte buffer.
     45      *
     46      * Note: Each Hotspot 2.0 Release 2 element will be wrapped inside a Vendor Specific element
     47      * in the ANQP response from the AP.  However, the lower layer (e.g. wpa_supplicant) should
     48      * already take care of parsing those elements out of Vendor Specific elements.  To be safe,
     49      * we will parse the Vendor Specific elements for non-Hotspot 2.0 Release elements or in
     50      * the case they're not parsed by the lower layer.
     51      *
     52      * @param infoID The ANQP element type
     53      * @param payload The buffer to read from
     54      * @return {@link com.android.server.wifi.hotspot2.anqp.ANQPElement}
     55      * @throws BufferUnderflowException
     56      * @throws ProtocolException
     57      */
     58     public static ANQPElement parseElement(Constants.ANQPElementType infoID, ByteBuffer payload)
     59             throws ProtocolException {
     60         switch (infoID) {
     61             case ANQPVenueName:
     62                 return VenueNameElement.parse(payload);
     63             case ANQPRoamingConsortium:
     64                 return RoamingConsortiumElement.parse(payload);
     65             case ANQPIPAddrAvailability:
     66                 return IPAddressTypeAvailabilityElement.parse(payload);
     67             case ANQPNAIRealm:
     68                 return NAIRealmElement.parse(payload);
     69             case ANQP3GPPNetwork:
     70                 return ThreeGPPNetworkElement.parse(payload);
     71             case ANQPDomName:
     72                 return DomainNameElement.parse(payload);
     73             case ANQPVendorSpec:
     74                 return parseVendorSpecificElement(payload);
     75             default:
     76                 throw new ProtocolException("Unknown element ID: " + infoID);
     77         }
     78     }
     79 
     80     /**
     81      * Parse a Hotspot 2.0 Release 2 ANQP element from the pass-in byte buffer.
     82      *
     83      * @param infoID The ANQP element ID
     84      * @param payload The buffer to read from
     85      * @return {@link com.android.server.wifi.hotspot2.anqp.ANQPElement}
     86      * @throws BufferUnderflowException
     87      * @throws ProtocolException
     88      */
     89     public static ANQPElement parseHS20Element(Constants.ANQPElementType infoID,
     90             ByteBuffer payload) throws ProtocolException {
     91         switch (infoID) {
     92             case HSFriendlyName:
     93                 return HSFriendlyNameElement.parse(payload);
     94             case HSWANMetrics:
     95                 return HSWanMetricsElement.parse(payload);
     96             case HSConnCapability:
     97                 return HSConnectionCapabilityElement.parse(payload);
     98             case HSOSUProviders:
     99                 return HSOsuProvidersElement.parse(payload);
    100             default:
    101                 throw new ProtocolException("Unknown element ID: " + infoID);
    102         }
    103     }
    104 
    105     /**
    106      * Parse the ANQP vendor specific element.  Currently only supports the vendor specific
    107      * element that contained Hotspot 2.0 ANQP-element.
    108      *
    109      * Format of a ANQP Vendor Specific element:
    110      * | OI | Type | Subtype | Reserved | Payload |
    111      *   3     1        1         1       variable
    112      *
    113      * @param payload The buffer to read from
    114      * @return {@link ANQPElement}
    115      * @throws BufferUnderflowException
    116      * @throws ProtocolException
    117      */
    118     private static ANQPElement parseVendorSpecificElement(ByteBuffer payload)
    119             throws ProtocolException {
    120         int oi = (int) ByteBufferReader.readInteger(payload, ByteOrder.BIG_ENDIAN, 3);
    121         int type = payload.get() & 0xFF;
    122 
    123         if (oi != VENDOR_SPECIFIC_HS20_OI || type != VENDOR_SPECIFIC_HS20_TYPE) {
    124             throw new ProtocolException("Unsupported vendor specific OI=" + oi + " type=" + type);
    125         }
    126 
    127         int subType = payload.get() & 0xFF;
    128         Constants.ANQPElementType hs20ID = Constants.mapHS20Element(subType);
    129         if (hs20ID == null) {
    130             throw new ProtocolException("Unsupported subtype: " + subType);
    131         }
    132         payload.get();     // Skip the reserved byte
    133         return parseHS20Element(hs20ID, payload);
    134     }
    135 }
    136