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; 18 19 import android.text.TextUtils; 20 21 import com.android.server.wifi.IMSIParameter; 22 import com.android.server.wifi.hotspot2.anqp.CellularNetwork; 23 import com.android.server.wifi.hotspot2.anqp.DomainNameElement; 24 import com.android.server.wifi.hotspot2.anqp.NAIRealmData; 25 import com.android.server.wifi.hotspot2.anqp.NAIRealmElement; 26 import com.android.server.wifi.hotspot2.anqp.RoamingConsortiumElement; 27 import com.android.server.wifi.hotspot2.anqp.ThreeGPPNetworkElement; 28 29 import java.util.List; 30 31 /** 32 * Utility class for providing matching functions against ANQP elements. 33 */ 34 public class ANQPMatcher { 35 /** 36 * Match the domain names in the ANQP element against the provider's FQDN and SIM credential. 37 * The Domain Name ANQP element might contain domains for 3GPP network (e.g. 38 * wlan.mnc*.mcc*.3gppnetwork.org), so we should match that against the provider's SIM 39 * credential if one is provided. 40 * 41 * @param element The Domain Name ANQP element 42 * @param fqdn The FQDN to compare against 43 * @param imsiParam The IMSI parameter of the provider (needed only for IMSI matching) 44 * @param simImsi The IMSI from the installed SIM cards that best matched provider's 45 * IMSI parameter (needed only for IMSI matching) 46 * @return true if a match is found 47 */ matchDomainName(DomainNameElement element, String fqdn, IMSIParameter imsiParam, String simImsi)48 public static boolean matchDomainName(DomainNameElement element, String fqdn, 49 IMSIParameter imsiParam, String simImsi) { 50 if (element == null) { 51 return false; 52 } 53 54 for (String domain : element.getDomains()) { 55 if (DomainMatcher.arg2SubdomainOfArg1(fqdn, domain)) { 56 return true; 57 } 58 59 if (imsiParam == null || simImsi == null) { 60 continue; 61 } 62 63 // Try to retrieve the MCC-MNC string from the domain (for 3GPP network domain) and 64 // match against the provider's SIM credential. 65 if (matchMccMnc(Utils.getMccMnc(Utils.splitDomain(domain)), imsiParam, simImsi)) { 66 return true; 67 } 68 } 69 return false; 70 } 71 72 /** 73 * Match the roaming consortium OIs in the ANQP element against the roaming consortium OIs 74 * of a provider. 75 * 76 * @param element The Roaming Consortium ANQP element 77 * @param providerOIs The roaming consortium OIs of the provider 78 * @param matchAll Indicates if a match with all OIs must be done 79 * @return true if a match is found 80 */ matchRoamingConsortium(RoamingConsortiumElement element, long[] providerOIs, boolean matchAll)81 public static boolean matchRoamingConsortium(RoamingConsortiumElement element, 82 long[] providerOIs, boolean matchAll) { 83 if (element == null) { 84 return false; 85 } 86 if (providerOIs == null) { 87 return false; 88 } 89 List<Long> rcOIs = element.getOIs(); 90 for (long oi : providerOIs) { 91 if (rcOIs.contains(oi)) { 92 if (!matchAll) { 93 return true; 94 } 95 } else if (matchAll) { 96 return false; 97 } 98 } 99 return matchAll; 100 } 101 102 /** 103 * Match the NAI realm in the ANQP element against the realm and authentication method of 104 * a provider. 105 * 106 * @param element The NAI Realm ANQP element 107 * @param realm The realm of the provider's credential 108 * @return true if there is a NAI Realm match, false otherwise 109 */ matchNAIRealm(NAIRealmElement element, String realm)110 public static boolean matchNAIRealm(NAIRealmElement element, String realm) { 111 if (element == null || element.getRealmDataList().isEmpty()) { 112 return false; 113 } 114 115 for (NAIRealmData realmData : element.getRealmDataList()) { 116 if (matchNAIRealmData(realmData, realm)) { 117 return true; 118 } 119 } 120 return false; 121 } 122 123 /** 124 * Match the 3GPP Network in the ANQP element against the SIM credential of a provider. 125 * 126 * @param element 3GPP Network ANQP element 127 * @param imsiParam The IMSI parameter of the provider's SIM credential 128 * @param simImsi The IMSI from the installed SIM cards that best matched provider's 129 * IMSI parameter 130 * @return true if a match is found 131 */ matchThreeGPPNetwork(ThreeGPPNetworkElement element, IMSIParameter imsiParam, String simImsi)132 public static boolean matchThreeGPPNetwork(ThreeGPPNetworkElement element, 133 IMSIParameter imsiParam, String simImsi) { 134 if (element == null) { 135 return false; 136 } 137 for (CellularNetwork network : element.getNetworks()) { 138 if (matchCellularNetwork(network, imsiParam, simImsi)) { 139 return true; 140 } 141 } 142 return false; 143 } 144 145 /** 146 * Match the given NAI Realm data against the realm and authentication method of a provider. 147 * 148 * @param realmData The NAI Realm data 149 * @param realm The realm of the provider's credential 150 * @return true if a match is found 151 */ matchNAIRealmData(NAIRealmData realmData, String realm)152 private static boolean matchNAIRealmData(NAIRealmData realmData, String realm) { 153 // Check for realm domain name match. 154 for (String realmStr : realmData.getRealms()) { 155 if (DomainMatcher.arg2SubdomainOfArg1(realm, realmStr)) { 156 return true; 157 } 158 } 159 return false; 160 } 161 162 /** 163 * Match a cellular network information in the 3GPP Network ANQP element against the SIM 164 * credential of a provider. 165 * 166 * @param network The cellular network that contained list of PLMNs 167 * @param imsiParam IMSI parameter of the provider 168 * @param simImsi The IMSI from the installed SIM cards that best matched provider's 169 * IMSI parameter 170 * @return true if a match is found 171 */ matchCellularNetwork(CellularNetwork network, IMSIParameter imsiParam, String simImsi)172 private static boolean matchCellularNetwork(CellularNetwork network, IMSIParameter imsiParam, 173 String simImsi) { 174 for (String plmn : network.getPlmns()) { 175 if (matchMccMnc(plmn, imsiParam, simImsi)) { 176 return true; 177 } 178 } 179 180 return false; 181 } 182 183 /** 184 * Match a MCC-MNC against the SIM credential of a provider. 185 * 186 * @param mccMnc The string containing MCC-MNC 187 * @param imsiParam The IMSI parameter of the provider 188 * @param simImsi The IMSI from the installed SIM cards that best matched provider's 189 * IMSI parameter 190 * @return true if a match is found 191 */ matchMccMnc(String mccMnc, IMSIParameter imsiParam, String simImsi)192 private static boolean matchMccMnc(String mccMnc, IMSIParameter imsiParam, 193 String simImsi) { 194 if (imsiParam == null || TextUtils.isEmpty(simImsi) || mccMnc == null) { 195 return false; 196 } 197 // Match against the IMSI parameter in the provider. 198 if (!imsiParam.matchesMccMnc(mccMnc)) { 199 return false; 200 } 201 // Additional check for verifying the match with IMSI from the SIM card, since the IMSI 202 // parameter might not contain the full 6-digit MCC MNC (e.g. IMSI parameter is an IMSI 203 // prefix that contained less than 6-digit of numbers "12345*"). 204 return simImsi.startsWith(mccMnc); 205 } 206 } 207