package com.android.server.wifi.hotspot2.anqp; import com.android.server.wifi.hotspot2.NetworkDetail; import java.net.ProtocolException; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Factory to build a collection of 802.11u ANQP elements from a byte buffer. */ public class ANQPFactory { private static final List BaseANQPSet1 = Arrays.asList( Constants.ANQPElementType.ANQPVenueName, Constants.ANQPElementType.ANQPRoamingConsortium, Constants.ANQPElementType.ANQPIPAddrAvailability, Constants.ANQPElementType.ANQPNAIRealm, Constants.ANQPElementType.ANQP3GPPNetwork, Constants.ANQPElementType.ANQPDomName); private static final List BaseANQPSet2 = Arrays.asList( Constants.ANQPElementType.ANQPVenueName, Constants.ANQPElementType.ANQPIPAddrAvailability, Constants.ANQPElementType.ANQPNAIRealm, Constants.ANQPElementType.ANQP3GPPNetwork, Constants.ANQPElementType.ANQPDomName); private static final List HS20ANQPSet = Arrays.asList( Constants.ANQPElementType.HSFriendlyName, Constants.ANQPElementType.HSWANMetrics, Constants.ANQPElementType.HSConnCapability); private static final List HS20ANQPSetwOSU = Arrays.asList( Constants.ANQPElementType.HSFriendlyName, Constants.ANQPElementType.HSWANMetrics, Constants.ANQPElementType.HSConnCapability, Constants.ANQPElementType.HSOSUProviders); public static List getBaseANQPSet(boolean includeRC) { return includeRC ? BaseANQPSet1 : BaseANQPSet2; } public static List getHS20ANQPSet(boolean includeOSU) { return includeOSU ? HS20ANQPSetwOSU : HS20ANQPSet; } public static List buildQueryList(NetworkDetail networkDetail, boolean matchSet, boolean osu) { List querySet = new ArrayList<>(); if (matchSet) { querySet.addAll(getBaseANQPSet(networkDetail.getAnqpOICount() > 0)); } if (networkDetail.getHSRelease() != null) { boolean includeOSU = osu && networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2; if (matchSet) { querySet.addAll(getHS20ANQPSet(includeOSU)); } else if (includeOSU) { querySet.add(Constants.ANQPElementType.HSOSUProviders); } } return querySet; } /** * Build 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 buildElement(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: if (payload.remaining() > 5) { int oi = payload.getInt(); if (oi != Constants.HS20_PREFIX) { return null; } int subType = payload.get() & Constants.BYTE_MASK; Constants.ANQPElementType hs20ID = Constants.mapHS20Element(subType); if (hs20ID == null) { throw new ProtocolException("Bad HS20 info ID: " + subType); } payload.get(); // Skip the reserved octet return buildHS20Element(hs20ID, payload); } else { return new GenericBlobElement(infoID, payload); } default: throw new ProtocolException("Unknown element ID: " + infoID); } } /** * Build 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 buildHS20Element(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 RawByteElement.parse(infoID, payload); default: throw new ProtocolException("Unknown element ID: " + infoID); } } }