Loading wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +14 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.net.wifi.hotspot2; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSP; import android.net.wifi.hotspot2.pps.Policy; import android.os.Parcelable; import android.os.Parcel; Loading @@ -28,13 +29,12 @@ import android.os.Parcel; * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0 * Release 2 Technical Specification. * * Currently, only HomeSP and Credential subtrees are supported. * * @hide */ public final class PasspointConfiguration implements Parcelable { public HomeSP homeSp = null; public Credential credential = null; public Policy policy = null; /** * Constructor for creating PasspointConfiguration with default values. Loading @@ -54,6 +54,9 @@ public final class PasspointConfiguration implements Parcelable { if (source.credential != null) { credential = new Credential(source.credential); } if (source.policy != null) { policy = new Policy(source.policy); } } } Loading @@ -66,6 +69,7 @@ public final class PasspointConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(homeSp, flags); dest.writeParcelable(credential, flags); dest.writeParcelable(policy, flags); } @Override Loading @@ -77,9 +81,10 @@ public final class PasspointConfiguration implements Parcelable { return false; } PasspointConfiguration that = (PasspointConfiguration) thatObject; return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) && (credential == null ? that.credential == null : credential.equals(that.credential)); return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) && (credential == null ? that.credential == null : credential.equals(that.credential)) && (policy == null) ? that.policy == null : policy.equals(that.policy); } /** Loading @@ -94,6 +99,9 @@ public final class PasspointConfiguration implements Parcelable { if (credential == null || !credential.validate()) { return false; } if (policy != null && !policy.validate()) { return false; } return true; } Loading @@ -104,6 +112,7 @@ public final class PasspointConfiguration implements Parcelable { PasspointConfiguration config = new PasspointConfiguration(); config.homeSp = in.readParcelable(null); config.credential = in.readParcelable(null); config.policy = in.readParcelable(null); return config; } @Override Loading wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java +452 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.net.wifi.hotspot2.omadm; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSP; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; import android.text.TextUtils; import android.util.Log; import android.util.Pair; Loading Loading @@ -168,12 +170,39 @@ public final class PPSMOParser { private static final String NODE_INNER_METHOD = "InnerMethod"; private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate"; private static final String NODE_CERTIFICATE_TYPE = "CertificateType"; private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256FingerPrint"; private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint"; private static final String NODE_REALM = "Realm"; private static final String NODE_SIM = "SIM"; private static final String NODE_SIM_IMSI = "IMSI"; private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus"; /** * Fields under Policy subtree. */ private static final String NODE_POLICY = "Policy"; private static final String NODE_PREFERRED_ROAMING_PARTNER_LIST = "PreferredRoamingPartnerList"; private static final String NODE_FQDN_MATCH = "FQDN_Match"; private static final String NODE_PRIORITY = "Priority"; private static final String NODE_COUNTRY = "Country"; private static final String NODE_MIN_BACKHAUL_THRESHOLD = "MinBackhaulThreshold"; private static final String NODE_NETWORK_TYPE = "NetworkType"; private static final String NODE_DOWNLINK_BANDWIDTH = "DLBandwidth"; private static final String NODE_UPLINK_BANDWIDTH = "ULBandwidth"; private static final String NODE_POLICY_UPDATE = "PolicyUpdate"; private static final String NODE_UPDATE_INTERVAL = "UpdateInterval"; private static final String NODE_UPDATE_METHOD = "UpdateMethod"; private static final String NODE_RESTRICTION = "Restriction"; private static final String NODE_URI = "URI"; private static final String NODE_TRUST_ROOT = "TrustRoot"; private static final String NODE_CERT_URL = "CertURL"; private static final String NODE_SP_EXCLUSION_LIST = "SPExclusionList"; private static final String NODE_REQUIRED_PROTO_PORT_TUPLE = "RequiredProtoPortTuple"; private static final String NODE_IP_PROTOCOL = "IPProtocol"; private static final String NODE_PORT_NUMBER = "PortNumber"; private static final String NODE_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue"; private static final String NODE_OTHER = "Other"; /** * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree. */ Loading Loading @@ -551,6 +580,9 @@ public final class PPSMOParser { case NODE_CREDENTIAL: config.credential = parseCredential(child); break; case NODE_POLICY: config.policy = parsePolicy(child); break; default: throw new ParsingException("Unknown node: " + child.getName()); } Loading Loading @@ -998,6 +1030,425 @@ public final class PPSMOParser { return simCred; } /** * Parse configurations under PerProviderSubscription/Policy subtree. * * @param node PPSNode representing the root of the PerProviderSubscription/Policy subtree * @return {@link Policy} * @throws ParsingException */ private static Policy parsePolicy(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for Policy"); } Policy policy = new Policy(); for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_PREFERRED_ROAMING_PARTNER_LIST: policy.preferredRoamingPartnerList = parsePreferredRoamingPartnerList(child); break; case NODE_MIN_BACKHAUL_THRESHOLD: parseMinBackhaulThreshold(child, policy); break; case NODE_POLICY_UPDATE: policy.policyUpdate = parseUpdateParameter(child); break; case NODE_SP_EXCLUSION_LIST: policy.excludedSsidList = parseSpExclusionList(child); break; case NODE_REQUIRED_PROTO_PORT_TUPLE: policy.requiredProtoPortMap = parseRequiredProtoPortTuple(child); break; case NODE_MAXIMUM_BSS_LOAD_VALUE: policy.maximumBssLoadValue = parseInteger(getPpsNodeValue(child)); break; default: throw new ParsingException("Unknown node under Policy: " + child.getName()); } } return policy; } /** * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/PreferredRoamingPartnerList subtree * @return List of {@link Policy#RoamingPartner} * @throws ParsingException */ private static List<Policy.RoamingPartner> parsePreferredRoamingPartnerList(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for PreferredRoamingPartnerList"); } List<Policy.RoamingPartner> partnerList = new ArrayList<>(); for (PPSNode child : node.getChildren()) { partnerList.add(parsePreferredRoamingPartner(child)); } return partnerList; } /** * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> subtree * @return {@link Policy#RoamingPartner} * @throws ParsingException */ private static Policy.RoamingPartner parsePreferredRoamingPartner(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for PreferredRoamingPartner " + "instance"); } Policy.RoamingPartner roamingPartner = new Policy.RoamingPartner(); for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_FQDN_MATCH: // FQDN_Match field is in the format of "[FQDN],[MatchInfo]", where [MatchInfo] // is either "exactMatch" for exact match of FQDN or "includeSubdomains" for // matching all FQDNs with the same sub-domain. String fqdnMatch = getPpsNodeValue(child); String[] fqdnMatchArray = fqdnMatch.split(","); if (fqdnMatchArray.length != 2) { throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch); } roamingPartner.fqdn = fqdnMatchArray[0]; if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) { roamingPartner.fqdnExactMatch = true; } else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) { roamingPartner.fqdnExactMatch = false; } else { throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch); } break; case NODE_PRIORITY: roamingPartner.priority = parseInteger(getPpsNodeValue(child)); break; case NODE_COUNTRY: roamingPartner.countries = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under PreferredRoamingPartnerList " + "instance " + child.getName()); } } return roamingPartner; } /** * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold subtree * into the given policy. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/MinBackhaulThreshold subtree * @param policy The policy to store the MinBackhualThreshold configuration * @throws ParsingException */ private static void parseMinBackhaulThreshold(PPSNode node, Policy policy) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for MinBackhaulThreshold"); } for (PPSNode child : node.getChildren()) { parseMinBackhaulThresholdInstance(child, policy); } } /** * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree * into the given policy. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree * @param policy The policy to store the MinBackhaulThreshold configuration * @throws ParsingException */ private static void parseMinBackhaulThresholdInstance(PPSNode node, Policy policy) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for MinBackhaulThreshold instance"); } String networkType = null; long downlinkBandwidth = Long.MIN_VALUE; long uplinkBandwidth = Long.MIN_VALUE; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_NETWORK_TYPE: networkType = getPpsNodeValue(child); break; case NODE_DOWNLINK_BANDWIDTH: try { downlinkBandwidth = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for downlink bandwidth: " + getPpsNodeValue(child)); } break; case NODE_UPLINK_BANDWIDTH: try { uplinkBandwidth = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for downlink bandwidth: " + getPpsNodeValue(child)); } break; default: throw new ParsingException("Unknown node under MinBackhaulThreshold instance " + child.getName()); } } if (networkType == null) { throw new ParsingException("Missing NetworkType field"); } if (TextUtils.equals(networkType, "home")) { policy.minHomeDownlinkBandwidth = downlinkBandwidth; policy.minHomeUplinkBandwidth = uplinkBandwidth; } else if (TextUtils.equals(networkType, "roaming")) { policy.minRoamingDownlinkBandwidth = downlinkBandwidth; policy.minRoamingUplinkBandwidth = uplinkBandwidth; } else { throw new ParsingException("Invalid network type: " + networkType); } } /** * Parse update parameters. This contained configurations from either * PerProviderSubscription/Policy/PolicyUpdate or PerProviderSubscription/SubscriptionUpdate * subtree. * * @param node PPSNode representing the root of the PerProviderSubscription/Policy/PolicyUpdate * or PerProviderSubscription/SubscriptionUpdate subtree * @return {@link UpdateParameter} * @throws ParsingException */ private static UpdateParameter parseUpdateParameter(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for Update Parameters"); } UpdateParameter updateParam = new UpdateParameter(); for (PPSNode child : node.getChildren()) { switch(child.getName()) { case NODE_UPDATE_INTERVAL: try { updateParam.updateIntervalInMinutes = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for update interval: " + getPpsNodeValue(child)); } break; case NODE_UPDATE_METHOD: updateParam.updateMethod = getPpsNodeValue(child); break; case NODE_RESTRICTION: updateParam.restriction = getPpsNodeValue(child); break; case NODE_URI: updateParam.serverUri = getPpsNodeValue(child); break; case NODE_USERNAME_PASSWORD: Pair<String, String> usernamePassword = parseUpdateUserCredential(child); updateParam.username = usernamePassword.first; updateParam.base64EncodedPassword = usernamePassword.second; break; case NODE_TRUST_ROOT: Pair<String, byte[]> trustRoot = parseUpdateTrustRoot(child); updateParam.trustRootCertUrl = trustRoot.first; updateParam.trustRootCertSha256Fingerprint = trustRoot.second; break; case NODE_OTHER: Log.d(TAG, "Ignore unsupported paramter: " + child.getName()); break; default: throw new ParsingException("Unknown node under Update Parameters: " + child.getName()); } } return updateParam; } /** * Parse username and password parameters associated with policy or subscription update. * This contained configurations under either * PerProviderSubscription/Policy/PolicyUpdate/UsernamePassword or * PerProviderSubscription/SubscriptionUpdate/UsernamePassword subtree. * * @param node PPSNode representing the root of the UsernamePassword subtree * @return Pair of username and password * @throws ParsingException */ private static Pair<String, String> parseUpdateUserCredential(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for UsernamePassword"); } String username = null; String password = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_USERNAME: username = getPpsNodeValue(child); break; case NODE_PASSWORD: password = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under UsernamePassword: " + child.getName()); } } return Pair.create(username, password); } /** * Parse the trust root parameters associated with policy or subscription update. * This contained configurations under either * PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or * PerProviderSubscription/SubscriptionUpdate/TrustRoot subtree. * * @param node PPSNode representing the root of the TrustRoot subtree * @return Pair of Certificate URL and fingerprint * @throws ParsingException */ private static Pair<String, byte[]> parseUpdateTrustRoot(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for TrustRoot"); } String certUrl = null; byte[] certFingerprint = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_CERT_URL: certUrl = getPpsNodeValue(child); break; case NODE_CERT_SHA256_FINGERPRINT: certFingerprint = parseHexString(getPpsNodeValue(child)); break; default: throw new ParsingException("Unknown node under TrustRoot: " + child.getName()); } } return Pair.create(certUrl, certFingerprint); } /** * Parse configurations under PerProviderSubscription/Policy/SPExclusionList subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/SPExclusionList subtree * @return Array of excluded SSIDs * @throws ParsingException */ private static String[] parseSpExclusionList(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for SPExclusionList"); } List<String> ssidList = new ArrayList<>(); for (PPSNode child : node.getChildren()) { ssidList.add(parseSpExclusionInstance(child)); } return ssidList.toArray(new String[ssidList.size()]); } /** * Parse configurations under PerProviderSubscription/Policy/SPExclusionList/<X+> subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/SPExclusionList/<X+> subtree * @return String * @throws ParsingException */ private static String parseSpExclusionInstance(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for SPExclusion instance"); } String ssid = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_SSID: ssid = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under SPExclusion instance"); } } return ssid; } /** * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/RequiredProtoPortTuple subtree * @return Map of IP Protocol to Port Number tuples * @throws ParsingException */ private static Map<Integer, String> parseRequiredProtoPortTuple(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple"); } Map<Integer, String> protoPortTupleMap = new HashMap<>(); for (PPSNode child : node.getChildren()) { Pair<Integer, String> protoPortTuple = parseProtoPortTuple(child); protoPortTupleMap.put(protoPortTuple.first, protoPortTuple.second); } return protoPortTupleMap; } /** * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> subtree * @return Pair of IP Protocol to Port Number tuple * @throws ParsingException */ private static Pair<Integer, String> parseProtoPortTuple(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple " + "instance"); } int proto = Integer.MIN_VALUE; String ports = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_IP_PROTOCOL: proto = parseInteger(getPpsNodeValue(child)); break; case NODE_PORT_NUMBER: ports = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under RequiredProtoPortTuple instance" + child.getName()); } } if (proto == Integer.MIN_VALUE) { throw new ParsingException("Missing IPProtocol field"); } if (ports == null) { throw new ParsingException("Missing PortNumber field"); } return Pair.create(proto, ports); } /** * Convert a hex string to a byte array. * Loading wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl 0 → 100644 +19 −0 Original line number Diff line number Diff line /** * Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps; parcelable Policy; Loading
wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java +14 −5 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.net.wifi.hotspot2; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSP; import android.net.wifi.hotspot2.pps.Policy; import android.os.Parcelable; import android.os.Parcel; Loading @@ -28,13 +29,12 @@ import android.os.Parcel; * For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0 * Release 2 Technical Specification. * * Currently, only HomeSP and Credential subtrees are supported. * * @hide */ public final class PasspointConfiguration implements Parcelable { public HomeSP homeSp = null; public Credential credential = null; public Policy policy = null; /** * Constructor for creating PasspointConfiguration with default values. Loading @@ -54,6 +54,9 @@ public final class PasspointConfiguration implements Parcelable { if (source.credential != null) { credential = new Credential(source.credential); } if (source.policy != null) { policy = new Policy(source.policy); } } } Loading @@ -66,6 +69,7 @@ public final class PasspointConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(homeSp, flags); dest.writeParcelable(credential, flags); dest.writeParcelable(policy, flags); } @Override Loading @@ -77,9 +81,10 @@ public final class PasspointConfiguration implements Parcelable { return false; } PasspointConfiguration that = (PasspointConfiguration) thatObject; return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) && (credential == null ? that.credential == null : credential.equals(that.credential)); return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) && (credential == null ? that.credential == null : credential.equals(that.credential)) && (policy == null) ? that.policy == null : policy.equals(that.policy); } /** Loading @@ -94,6 +99,9 @@ public final class PasspointConfiguration implements Parcelable { if (credential == null || !credential.validate()) { return false; } if (policy != null && !policy.validate()) { return false; } return true; } Loading @@ -104,6 +112,7 @@ public final class PasspointConfiguration implements Parcelable { PasspointConfiguration config = new PasspointConfiguration(); config.homeSp = in.readParcelable(null); config.credential = in.readParcelable(null); config.policy = in.readParcelable(null); return config; } @Override Loading
wifi/java/android/net/wifi/hotspot2/omadm/PPSMOParser.java +452 −1 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.net.wifi.hotspot2.omadm; import android.net.wifi.hotspot2.PasspointConfiguration; import android.net.wifi.hotspot2.pps.Credential; import android.net.wifi.hotspot2.pps.HomeSP; import android.net.wifi.hotspot2.pps.Policy; import android.net.wifi.hotspot2.pps.UpdateParameter; import android.text.TextUtils; import android.util.Log; import android.util.Pair; Loading Loading @@ -168,12 +170,39 @@ public final class PPSMOParser { private static final String NODE_INNER_METHOD = "InnerMethod"; private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate"; private static final String NODE_CERTIFICATE_TYPE = "CertificateType"; private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256FingerPrint"; private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint"; private static final String NODE_REALM = "Realm"; private static final String NODE_SIM = "SIM"; private static final String NODE_SIM_IMSI = "IMSI"; private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus"; /** * Fields under Policy subtree. */ private static final String NODE_POLICY = "Policy"; private static final String NODE_PREFERRED_ROAMING_PARTNER_LIST = "PreferredRoamingPartnerList"; private static final String NODE_FQDN_MATCH = "FQDN_Match"; private static final String NODE_PRIORITY = "Priority"; private static final String NODE_COUNTRY = "Country"; private static final String NODE_MIN_BACKHAUL_THRESHOLD = "MinBackhaulThreshold"; private static final String NODE_NETWORK_TYPE = "NetworkType"; private static final String NODE_DOWNLINK_BANDWIDTH = "DLBandwidth"; private static final String NODE_UPLINK_BANDWIDTH = "ULBandwidth"; private static final String NODE_POLICY_UPDATE = "PolicyUpdate"; private static final String NODE_UPDATE_INTERVAL = "UpdateInterval"; private static final String NODE_UPDATE_METHOD = "UpdateMethod"; private static final String NODE_RESTRICTION = "Restriction"; private static final String NODE_URI = "URI"; private static final String NODE_TRUST_ROOT = "TrustRoot"; private static final String NODE_CERT_URL = "CertURL"; private static final String NODE_SP_EXCLUSION_LIST = "SPExclusionList"; private static final String NODE_REQUIRED_PROTO_PORT_TUPLE = "RequiredProtoPortTuple"; private static final String NODE_IP_PROTOCOL = "IPProtocol"; private static final String NODE_PORT_NUMBER = "PortNumber"; private static final String NODE_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue"; private static final String NODE_OTHER = "Other"; /** * URN (Unique Resource Name) for PerProviderSubscription Management Object Tree. */ Loading Loading @@ -551,6 +580,9 @@ public final class PPSMOParser { case NODE_CREDENTIAL: config.credential = parseCredential(child); break; case NODE_POLICY: config.policy = parsePolicy(child); break; default: throw new ParsingException("Unknown node: " + child.getName()); } Loading Loading @@ -998,6 +1030,425 @@ public final class PPSMOParser { return simCred; } /** * Parse configurations under PerProviderSubscription/Policy subtree. * * @param node PPSNode representing the root of the PerProviderSubscription/Policy subtree * @return {@link Policy} * @throws ParsingException */ private static Policy parsePolicy(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for Policy"); } Policy policy = new Policy(); for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_PREFERRED_ROAMING_PARTNER_LIST: policy.preferredRoamingPartnerList = parsePreferredRoamingPartnerList(child); break; case NODE_MIN_BACKHAUL_THRESHOLD: parseMinBackhaulThreshold(child, policy); break; case NODE_POLICY_UPDATE: policy.policyUpdate = parseUpdateParameter(child); break; case NODE_SP_EXCLUSION_LIST: policy.excludedSsidList = parseSpExclusionList(child); break; case NODE_REQUIRED_PROTO_PORT_TUPLE: policy.requiredProtoPortMap = parseRequiredProtoPortTuple(child); break; case NODE_MAXIMUM_BSS_LOAD_VALUE: policy.maximumBssLoadValue = parseInteger(getPpsNodeValue(child)); break; default: throw new ParsingException("Unknown node under Policy: " + child.getName()); } } return policy; } /** * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/PreferredRoamingPartnerList subtree * @return List of {@link Policy#RoamingPartner} * @throws ParsingException */ private static List<Policy.RoamingPartner> parsePreferredRoamingPartnerList(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for PreferredRoamingPartnerList"); } List<Policy.RoamingPartner> partnerList = new ArrayList<>(); for (PPSNode child : node.getChildren()) { partnerList.add(parsePreferredRoamingPartner(child)); } return partnerList; } /** * Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> subtree * @return {@link Policy#RoamingPartner} * @throws ParsingException */ private static Policy.RoamingPartner parsePreferredRoamingPartner(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for PreferredRoamingPartner " + "instance"); } Policy.RoamingPartner roamingPartner = new Policy.RoamingPartner(); for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_FQDN_MATCH: // FQDN_Match field is in the format of "[FQDN],[MatchInfo]", where [MatchInfo] // is either "exactMatch" for exact match of FQDN or "includeSubdomains" for // matching all FQDNs with the same sub-domain. String fqdnMatch = getPpsNodeValue(child); String[] fqdnMatchArray = fqdnMatch.split(","); if (fqdnMatchArray.length != 2) { throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch); } roamingPartner.fqdn = fqdnMatchArray[0]; if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) { roamingPartner.fqdnExactMatch = true; } else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) { roamingPartner.fqdnExactMatch = false; } else { throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch); } break; case NODE_PRIORITY: roamingPartner.priority = parseInteger(getPpsNodeValue(child)); break; case NODE_COUNTRY: roamingPartner.countries = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under PreferredRoamingPartnerList " + "instance " + child.getName()); } } return roamingPartner; } /** * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold subtree * into the given policy. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/MinBackhaulThreshold subtree * @param policy The policy to store the MinBackhualThreshold configuration * @throws ParsingException */ private static void parseMinBackhaulThreshold(PPSNode node, Policy policy) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for MinBackhaulThreshold"); } for (PPSNode child : node.getChildren()) { parseMinBackhaulThresholdInstance(child, policy); } } /** * Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree * into the given policy. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree * @param policy The policy to store the MinBackhaulThreshold configuration * @throws ParsingException */ private static void parseMinBackhaulThresholdInstance(PPSNode node, Policy policy) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for MinBackhaulThreshold instance"); } String networkType = null; long downlinkBandwidth = Long.MIN_VALUE; long uplinkBandwidth = Long.MIN_VALUE; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_NETWORK_TYPE: networkType = getPpsNodeValue(child); break; case NODE_DOWNLINK_BANDWIDTH: try { downlinkBandwidth = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for downlink bandwidth: " + getPpsNodeValue(child)); } break; case NODE_UPLINK_BANDWIDTH: try { uplinkBandwidth = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for downlink bandwidth: " + getPpsNodeValue(child)); } break; default: throw new ParsingException("Unknown node under MinBackhaulThreshold instance " + child.getName()); } } if (networkType == null) { throw new ParsingException("Missing NetworkType field"); } if (TextUtils.equals(networkType, "home")) { policy.minHomeDownlinkBandwidth = downlinkBandwidth; policy.minHomeUplinkBandwidth = uplinkBandwidth; } else if (TextUtils.equals(networkType, "roaming")) { policy.minRoamingDownlinkBandwidth = downlinkBandwidth; policy.minRoamingUplinkBandwidth = uplinkBandwidth; } else { throw new ParsingException("Invalid network type: " + networkType); } } /** * Parse update parameters. This contained configurations from either * PerProviderSubscription/Policy/PolicyUpdate or PerProviderSubscription/SubscriptionUpdate * subtree. * * @param node PPSNode representing the root of the PerProviderSubscription/Policy/PolicyUpdate * or PerProviderSubscription/SubscriptionUpdate subtree * @return {@link UpdateParameter} * @throws ParsingException */ private static UpdateParameter parseUpdateParameter(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for Update Parameters"); } UpdateParameter updateParam = new UpdateParameter(); for (PPSNode child : node.getChildren()) { switch(child.getName()) { case NODE_UPDATE_INTERVAL: try { updateParam.updateIntervalInMinutes = Long.parseLong(getPpsNodeValue(child)); } catch (NumberFormatException e) { throw new ParsingException("Invalid value for update interval: " + getPpsNodeValue(child)); } break; case NODE_UPDATE_METHOD: updateParam.updateMethod = getPpsNodeValue(child); break; case NODE_RESTRICTION: updateParam.restriction = getPpsNodeValue(child); break; case NODE_URI: updateParam.serverUri = getPpsNodeValue(child); break; case NODE_USERNAME_PASSWORD: Pair<String, String> usernamePassword = parseUpdateUserCredential(child); updateParam.username = usernamePassword.first; updateParam.base64EncodedPassword = usernamePassword.second; break; case NODE_TRUST_ROOT: Pair<String, byte[]> trustRoot = parseUpdateTrustRoot(child); updateParam.trustRootCertUrl = trustRoot.first; updateParam.trustRootCertSha256Fingerprint = trustRoot.second; break; case NODE_OTHER: Log.d(TAG, "Ignore unsupported paramter: " + child.getName()); break; default: throw new ParsingException("Unknown node under Update Parameters: " + child.getName()); } } return updateParam; } /** * Parse username and password parameters associated with policy or subscription update. * This contained configurations under either * PerProviderSubscription/Policy/PolicyUpdate/UsernamePassword or * PerProviderSubscription/SubscriptionUpdate/UsernamePassword subtree. * * @param node PPSNode representing the root of the UsernamePassword subtree * @return Pair of username and password * @throws ParsingException */ private static Pair<String, String> parseUpdateUserCredential(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for UsernamePassword"); } String username = null; String password = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_USERNAME: username = getPpsNodeValue(child); break; case NODE_PASSWORD: password = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under UsernamePassword: " + child.getName()); } } return Pair.create(username, password); } /** * Parse the trust root parameters associated with policy or subscription update. * This contained configurations under either * PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or * PerProviderSubscription/SubscriptionUpdate/TrustRoot subtree. * * @param node PPSNode representing the root of the TrustRoot subtree * @return Pair of Certificate URL and fingerprint * @throws ParsingException */ private static Pair<String, byte[]> parseUpdateTrustRoot(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for TrustRoot"); } String certUrl = null; byte[] certFingerprint = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_CERT_URL: certUrl = getPpsNodeValue(child); break; case NODE_CERT_SHA256_FINGERPRINT: certFingerprint = parseHexString(getPpsNodeValue(child)); break; default: throw new ParsingException("Unknown node under TrustRoot: " + child.getName()); } } return Pair.create(certUrl, certFingerprint); } /** * Parse configurations under PerProviderSubscription/Policy/SPExclusionList subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/SPExclusionList subtree * @return Array of excluded SSIDs * @throws ParsingException */ private static String[] parseSpExclusionList(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for SPExclusionList"); } List<String> ssidList = new ArrayList<>(); for (PPSNode child : node.getChildren()) { ssidList.add(parseSpExclusionInstance(child)); } return ssidList.toArray(new String[ssidList.size()]); } /** * Parse configurations under PerProviderSubscription/Policy/SPExclusionList/<X+> subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/SPExclusionList/<X+> subtree * @return String * @throws ParsingException */ private static String parseSpExclusionInstance(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for SPExclusion instance"); } String ssid = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_SSID: ssid = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under SPExclusion instance"); } } return ssid; } /** * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/RequiredProtoPortTuple subtree * @return Map of IP Protocol to Port Number tuples * @throws ParsingException */ private static Map<Integer, String> parseRequiredProtoPortTuple(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple"); } Map<Integer, String> protoPortTupleMap = new HashMap<>(); for (PPSNode child : node.getChildren()) { Pair<Integer, String> protoPortTuple = parseProtoPortTuple(child); protoPortTupleMap.put(protoPortTuple.first, protoPortTuple.second); } return protoPortTupleMap; } /** * Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> * subtree. * * @param node PPSNode representing the root of the * PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> subtree * @return Pair of IP Protocol to Port Number tuple * @throws ParsingException */ private static Pair<Integer, String> parseProtoPortTuple(PPSNode node) throws ParsingException { if (node.isLeaf()) { throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple " + "instance"); } int proto = Integer.MIN_VALUE; String ports = null; for (PPSNode child : node.getChildren()) { switch (child.getName()) { case NODE_IP_PROTOCOL: proto = parseInteger(getPpsNodeValue(child)); break; case NODE_PORT_NUMBER: ports = getPpsNodeValue(child); break; default: throw new ParsingException("Unknown node under RequiredProtoPortTuple instance" + child.getName()); } } if (proto == Integer.MIN_VALUE) { throw new ParsingException("Missing IPProtocol field"); } if (ports == null) { throw new ParsingException("Missing PortNumber field"); } return Pair.create(proto, ports); } /** * Convert a hex string to a byte array. * Loading
wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl 0 → 100644 +19 −0 Original line number Diff line number Diff line /** * Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps; parcelable Policy;