blob: 89bcfcb787e7f56796d12eefb87f8b1edcca43b1 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi.hotspot2.anqp;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.wifi.ByteBufferReader;
import java.net.ProtocolException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
/**
* Factory to build a collection of 802.11u ANQP elements from a byte buffer.
*/
public class ANQPParser {
/**
* The OI value for Hotspot 2.0 ANQP-element.
*/
@VisibleForTesting
public static final int VENDOR_SPECIFIC_HS20_OI = 0x506F9A;
/**
* The Type value for Hotspot 2.0 ANQP-element.
*/
@VisibleForTesting
public static final int VENDOR_SPECIFIC_HS20_TYPE = 0x11;
/**
* Parse an ANQP element from the pass-in byte buffer.
*
* Note: Each Hotspot 2.0 Release 2 element will be wrapped inside a Vendor Specific element
* in the ANQP response from the AP. However, the lower layer (e.g. wpa_supplicant) should
* already take care of parsing those elements out of Vendor Specific elements. To be safe,
* we will parse the Vendor Specific elements for non-Hotspot 2.0 Release elements or in
* the case they're not parsed by the lower layer.
*
* @param infoID The ANQP element type
* @param payload The buffer to read from
* @return {@link com.android.server.wifi.hotspot2.anqp.ANQPElement}
* @throws BufferUnderflowException
* @throws ProtocolException
*/
public static ANQPElement parseElement(Constants.ANQPElementType infoID, ByteBuffer payload)
throws ProtocolException {
switch (infoID) {
case ANQPVenueName:
return VenueNameElement.parse(payload);
case ANQPRoamingConsortium:
return RoamingConsortiumElement.parse(payload);
case ANQPIPAddrAvailability:
return IPAddressTypeAvailabilityElement.parse(payload);
case ANQPNAIRealm:
return NAIRealmElement.parse(payload);
case ANQP3GPPNetwork:
return ThreeGPPNetworkElement.parse(payload);
case ANQPDomName:
return DomainNameElement.parse(payload);
case ANQPVendorSpec:
return parseVendorSpecificElement(payload);
default:
throw new ProtocolException("Unknown element ID: " + infoID);
}
}
/**
* Parse a Hotspot 2.0 Release 2 ANQP element from the pass-in byte buffer.
*
* @param infoID The ANQP element ID
* @param payload The buffer to read from
* @return {@link com.android.server.wifi.hotspot2.anqp.ANQPElement}
* @throws BufferUnderflowException
* @throws ProtocolException
*/
public static ANQPElement parseHS20Element(Constants.ANQPElementType infoID,
ByteBuffer payload) throws ProtocolException {
switch (infoID) {
case HSFriendlyName:
return HSFriendlyNameElement.parse(payload);
case HSWANMetrics:
return HSWanMetricsElement.parse(payload);
case HSConnCapability:
return HSConnectionCapabilityElement.parse(payload);
case HSOSUProviders:
return HSOsuProvidersElement.parse(payload);
default:
throw new ProtocolException("Unknown element ID: " + infoID);
}
}
/**
* Parse the ANQP vendor specific element. Currently only supports the vendor specific
* element that contained Hotspot 2.0 ANQP-element.
*
* Format of a ANQP Vendor Specific element:
* | OI | Type | Subtype | Reserved | Payload |
* 3 1 1 1 variable
*
* @param payload The buffer to read from
* @return {@link ANQPElement}
* @throws BufferUnderflowException
* @throws ProtocolException
*/
private static ANQPElement parseVendorSpecificElement(ByteBuffer payload)
throws ProtocolException {
int oi = (int) ByteBufferReader.readInteger(payload, ByteOrder.BIG_ENDIAN, 3);
int type = payload.get() & 0xFF;
if (oi != VENDOR_SPECIFIC_HS20_OI || type != VENDOR_SPECIFIC_HS20_TYPE) {
throw new ProtocolException("Unsupported vendor specific OI=" + oi + " type=" + type);
}
int subType = payload.get() & 0xFF;
Constants.ANQPElementType hs20ID = Constants.mapHS20Element(subType);
if (hs20ID == null) {
throw new ProtocolException("Unsupported subtype: " + subType);
}
payload.get(); // Skip the reserved byte
return parseHS20Element(hs20ID, payload);
}
}