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;
18 
19 import android.text.TextUtils;
20 
21 /**
22  * Class for storing an IMSI (International Mobile Subscriber Identity) parameter.  The IMSI
23  * contains number (up to 15) of numerical digits.  When an IMSI ends with a '*', the specified
24  * IMSI is a prefix.
25  */
26 public class IMSIParameter {
27     /**
28      * MCC (Mobile Country Code) is a 3 digit number and MNC (Mobile Network Code) is also a 3
29      * digit number.
30      */
31     public static final int MCC_MNC_LENGTH = 6;
32 
33     private static final int MAX_IMSI_LENGTH = 15;
34 
35     private final String mImsi;
36     private final boolean mPrefix;
37 
IMSIParameter(String imsi, boolean prefix)38     public IMSIParameter(String imsi, boolean prefix) {
39         mImsi = imsi;
40         mPrefix = prefix;
41     }
42 
43     /**
44      * Build an IMSIParameter object from the given string.  A null will be returned for a
45      * malformed string.
46      *
47      * @param imsi The IMSI string
48      * @return {@link IMSIParameter}
49      */
build(String imsi)50     public static IMSIParameter build(String imsi) {
51         if (TextUtils.isEmpty(imsi)) {
52             return null;
53         }
54         if (imsi.length() > MAX_IMSI_LENGTH) {
55             return null;
56         }
57 
58         // Detect the first non-digit character.
59         int nonDigit;
60         char stopChar = '\0';
61         for (nonDigit = 0; nonDigit < imsi.length(); nonDigit++) {
62             stopChar = imsi.charAt(nonDigit);
63             if (stopChar < '0' || stopChar > '9') {
64                 break;
65             }
66         }
67 
68         if (nonDigit == imsi.length()) {
69             // Full IMSI.
70             return new IMSIParameter(imsi, false);
71         }
72         else if (nonDigit == imsi.length()-1 && stopChar == '*') {
73             // IMSI prefix.
74             return new IMSIParameter(imsi.substring(0, nonDigit), true);
75         }
76         return null;
77     }
78 
79     /**
80      * Perform matching against the given full IMSI.
81      *
82      * @param fullIMSI The full IMSI to match against
83      * @return true if matched
84      */
matchesImsi(String fullIMSI)85     public boolean matchesImsi(String fullIMSI) {
86         if (fullIMSI == null) {
87             return false;
88         }
89 
90         if (mPrefix) {
91             // Prefix matching.
92             return mImsi.regionMatches(false, 0, fullIMSI, 0, mImsi.length());
93         } else {
94             // Exact matching.
95             return mImsi.equals(fullIMSI);
96         }
97     }
98 
99     /**
100      * Perform matching against the given MCC-MNC (Mobile Country Code and Mobile Network
101      * Code) combination.
102      *
103      * @param mccMnc The MCC-MNC to match against
104      * @return true if matched
105      */
matchesMccMnc(String mccMnc)106     public boolean matchesMccMnc(String mccMnc) {
107         if (mccMnc == null) {
108             return false;
109         }
110         if (mccMnc.length() != MCC_MNC_LENGTH) {
111             return false;
112         }
113         int checkLength = MCC_MNC_LENGTH;
114         if (mPrefix && mImsi.length() < MCC_MNC_LENGTH) {
115             checkLength = mImsi.length();
116         }
117         return mImsi.regionMatches(false, 0, mccMnc, 0, checkLength);
118     }
119 
120     @Override
equals(Object thatObject)121     public boolean equals(Object thatObject) {
122         if (this == thatObject) {
123             return true;
124         }
125         if (!(thatObject instanceof IMSIParameter)) {
126             return false;
127         }
128 
129         IMSIParameter that = (IMSIParameter) thatObject;
130         return mPrefix == that.mPrefix && TextUtils.equals(mImsi, that.mImsi);
131     }
132 
133     @Override
hashCode()134     public int hashCode() {
135         int result = mImsi != null ? mImsi.hashCode() : 0;
136         result = 31 * result + (mPrefix ? 1 : 0);
137         return result;
138     }
139 
140     @Override
toString()141     public String toString() {
142         if (mPrefix) {
143             return mImsi + '*';
144         }
145         else {
146             return mImsi;
147         }
148     }
149 }
150