HomeSP.java revision 71a988c8e9859244b83cd55bb6b6ee913fcaf95c
1package com.android.server.wifi.hotspot2.pps;
2
3import com.android.server.wifi.anqp.ANQPElement;
4import com.android.server.wifi.anqp.CellularNetwork;
5import com.android.server.wifi.anqp.DomainNameElement;
6import com.android.server.wifi.anqp.HSConnectionCapabilityElement;
7import com.android.server.wifi.anqp.HSWanMetricsElement;
8import com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement;
9import com.android.server.wifi.anqp.NAIRealmData;
10import com.android.server.wifi.anqp.NAIRealmElement;
11import com.android.server.wifi.anqp.RoamingConsortiumElement;
12import com.android.server.wifi.anqp.ThreeGPPNetworkElement;
13import com.android.server.wifi.hotspot2.AuthMatch;
14import com.android.server.wifi.hotspot2.NetworkInfo;
15import com.android.server.wifi.hotspot2.PasspointMatch;
16import com.android.server.wifi.hotspot2.Utils;
17
18import java.util.ArrayList;
19import java.util.EnumMap;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
23
24import static com.android.server.wifi.anqp.Constants.ANQPElementType;
25
26public class HomeSP {
27    private final Map<String, String> mSSIDs;        // SSID, HESSID, [0,N]
28    private final String mFQDN;
29    private final DomainMatcher mDomainMatcher;
30    private final Set<Long> mRoamingConsortiums;    // [0,N]
31    private final Set<Long> mMatchAnyOIs;           // [0,N]
32    private final List<Long> mMatchAllOIs;          // [0,N]
33
34    private final Credential mCredential;
35
36    // Informational:
37    private final String mFriendlyName;             // [1]
38    private final String mIconURL;                  // [0,1]
39
40    public HomeSP(Map<String, String> ssidMap,
41                   /*@NotNull*/ String fqdn,
42                   /*@NotNull*/ Set<Long> roamingConsortiums,
43                   /*@NotNull*/ Set<String> otherHomePartners,
44                   /*@NotNull*/ Set<Long> matchAnyOIs,
45                   /*@NotNull*/ List<Long> matchAllOIs,
46                   String friendlyName,
47                   String iconURL,
48                   Credential credential) {
49
50        mSSIDs = ssidMap;
51        List<List<String>> otherPartners = new ArrayList<List<String>>(otherHomePartners.size());
52        for (String otherPartner : otherHomePartners) {
53            otherPartners.add(Utils.splitDomain(otherPartner));
54        }
55        mFQDN = fqdn;
56        mDomainMatcher = new DomainMatcher(Utils.splitDomain(fqdn), otherPartners);
57        mRoamingConsortiums = roamingConsortiums;
58        mMatchAnyOIs = matchAnyOIs;
59        mMatchAllOIs = matchAllOIs;
60        mFriendlyName = friendlyName;
61        mIconURL = iconURL;
62        mCredential = credential;
63    }
64
65    public PasspointMatch match(NetworkInfo networkInfo, List<ANQPElement> anqpElements) {
66
67        if (mSSIDs.containsKey(networkInfo.getSSID())) {
68            String hessid = mSSIDs.get(networkInfo.getSSID());
69            if (hessid == null || networkInfo.getHESSID().equals(hessid)) {
70                System.out.println("-- SSID");
71                return PasspointMatch.HomeProvider;
72            }
73        }
74
75        List<Long> allOIs = null;
76
77        if (networkInfo.getRoamingConsortiums() != null) {
78            allOIs = new ArrayList<Long>();
79            for (long oi : networkInfo.getRoamingConsortiums()) {
80                allOIs.add(oi);
81            }
82        }
83
84        Map<ANQPElementType, ANQPElement> anqpElementMap = null;
85
86        if (anqpElements != null) {
87            anqpElementMap = new EnumMap<ANQPElementType, ANQPElement>(ANQPElementType.class);
88            for (ANQPElement element : anqpElements) {
89                anqpElementMap.put(element.getID(), element);
90                if (element.getID() == ANQPElementType.ANQPRoamingConsortium) {
91                    RoamingConsortiumElement rcElement = (RoamingConsortiumElement) element;
92                    if (!rcElement.getOIs().isEmpty()) {
93                        if (allOIs == null) {
94                            allOIs = new ArrayList<Long>(rcElement.getOIs());
95                        } else {
96                            allOIs.addAll(rcElement.getOIs());
97                        }
98                    }
99                }
100            }
101        }
102
103        // !!! wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
104
105        if (allOIs != null) {
106            if (!mRoamingConsortiums.isEmpty()) {
107                for (long oi : allOIs) {
108                    if (mRoamingConsortiums.contains(oi)) {
109                        System.out.println("-- RC");
110                        return PasspointMatch.HomeProvider;
111                    }
112                }
113            }
114            if (!mMatchAnyOIs.isEmpty() || !mMatchAllOIs.isEmpty()) {
115                for (long anOI : allOIs) {
116
117                    boolean oneMatchesAll = !mMatchAllOIs.isEmpty();
118
119                    for (long spOI : mMatchAllOIs) {
120                        if (spOI != anOI) {
121                            oneMatchesAll = false;
122                            break;
123                        }
124                    }
125
126                    if (oneMatchesAll) {
127                        System.out.println("-- 1inAll");
128                        return PasspointMatch.HomeProvider;
129                    }
130
131                    if (mMatchAnyOIs.contains(anOI)) {
132                        System.out.println("-- 1ofAll");
133                        return PasspointMatch.HomeProvider;
134                    }
135                }
136            }
137        }
138
139        if (anqpElementMap == null) {
140            return PasspointMatch.Incomplete;
141        }
142
143        DomainNameElement domainNameElement =
144                (DomainNameElement) anqpElementMap.get(ANQPElementType.ANQPDomName);
145        NAIRealmElement naiRealmElement =
146                (NAIRealmElement) anqpElementMap.get(ANQPElementType.ANQPNAIRealm);
147        ThreeGPPNetworkElement threeGPPNetworkElement =
148                (ThreeGPPNetworkElement) anqpElementMap.get(ANQPElementType.ANQP3GPPNetwork);
149
150        // For future policy decisions:
151        IPAddressTypeAvailabilityElement ipAddressAvailabilityElement =
152                (IPAddressTypeAvailabilityElement) anqpElementMap.get(
153                        ANQPElementType.ANQPIPAddrAvailability);
154        HSConnectionCapabilityElement hsConnCapElement =
155                (HSConnectionCapabilityElement) anqpElementMap.get(
156                        ANQPElementType.HSConnCapability);
157        HSWanMetricsElement hsWanMetricsElement =
158                (HSWanMetricsElement) anqpElementMap.get(ANQPElementType.HSWANMetrics);
159
160        if (domainNameElement != null) {
161            for (String domain : domainNameElement.getDomains()) {
162                DomainMatcher.Match match = mDomainMatcher.isSubDomain(Utils.splitDomain(domain));
163                if (match != DomainMatcher.Match.None) {
164                    return PasspointMatch.HomeProvider;
165                }
166            }
167        }
168
169        if (naiRealmElement != null) {
170            AuthMatch authMatch = matchRealms(naiRealmElement, threeGPPNetworkElement);
171            if (authMatch != AuthMatch.None) {
172                return PasspointMatch.RoamingProvider;
173            }
174        }
175        return PasspointMatch.None;
176    }
177
178    private AuthMatch matchRealms(NAIRealmElement naiRealmElement,
179                                  ThreeGPPNetworkElement threeGPPNetworkElement) {
180        List<String> credRealm = Utils.splitDomain(mCredential.getRealm());
181
182        for (NAIRealmData naiRealmData : naiRealmElement.getRealmData()) {
183
184            DomainMatcher.Match match = DomainMatcher.Match.None;
185            for (String anRealm : naiRealmData.getRealms()) {
186                List<String> anRealmLabels = Utils.splitDomain(anRealm);
187                match = mDomainMatcher.isSubDomain(anRealmLabels);
188                if (match != DomainMatcher.Match.None) {
189                    break;
190                }
191                if (anRealmLabels.equals(credRealm)) {
192                    match = DomainMatcher.Match.Secondary;
193                    break;
194                }
195            }
196
197            if (match != DomainMatcher.Match.None) {
198                if (mCredential.getImsi() != null) {
199                    // All the device has is one of EAP-SIM, AKA or AKA',
200                    // so a 3GPP element must appear and contain a matching MNC/MCC
201                    if (threeGPPNetworkElement == null) {
202                        return AuthMatch.None;
203                    }
204                    for (CellularNetwork network : threeGPPNetworkElement.getPlmns()) {
205                        if (network.matchIMSI(mCredential.getImsi())) {
206                            AuthMatch authMatch =
207                                    naiRealmData.matchEAPMethods(mCredential.getEAPMethod());
208                            if (authMatch != AuthMatch.None) {
209                                return authMatch;
210                            }
211                        }
212                    }
213                } else {
214                    AuthMatch authMatch = naiRealmData.matchEAPMethods(mCredential.getEAPMethod());
215                    if (authMatch != AuthMatch.None) {
216                        // Note: Something more intelligent could be done here based on the
217                        // authMatch value. It may be useful to have a secondary score to
218                        // distinguish more predictable EAP method/parameter matching.
219                        return authMatch;
220                    }
221                }
222            }
223        }
224        return AuthMatch.None;
225    }
226
227    public String getFQDN() {
228        return mFQDN;
229    }
230
231    @Override
232    public boolean equals(Object thatObject) {
233        if (this == thatObject) {
234            return true;
235        } else if (thatObject == null || getClass() != thatObject.getClass()) {
236            return false;
237        }
238
239        HomeSP that = (HomeSP) thatObject;
240        return mFQDN.equals(that.mFQDN);
241
242    }
243
244    @Override
245    public int hashCode() {
246        return mFQDN.hashCode();
247    }
248
249    @Override
250    public String toString() {
251        return "HomeSP{" +
252                "mSSIDs=" + mSSIDs +
253                ", mFQDN='" + mFQDN + '\'' +
254                ", mDomainMatcher=" + mDomainMatcher +
255                ", mRoamingConsortiums={" + Utils.roamingConsortiumsToString(mRoamingConsortiums) +
256                '}' +
257                ", mMatchAnyOIs={" + Utils.roamingConsortiumsToString(mMatchAnyOIs) + '}' +
258                ", mMatchAllOIs={" + Utils.roamingConsortiumsToString(mMatchAllOIs) + '}' +
259                ", mCredential=" + mCredential +
260                ", mFriendlyName='" + mFriendlyName + '\'' +
261                ", mIconURL='" + mIconURL + '\'' +
262                '}';
263    }
264}
265