PasspointMatchInfo.java revision ef1567e413c9ed5f5c4fdb9e354861632f7b2f87
1package com.android.server.wifi.hotspot2; 2 3import com.android.server.wifi.anqp.ANQPElement; 4import com.android.server.wifi.anqp.Constants; 5import com.android.server.wifi.anqp.HSConnectionCapabilityElement; 6import com.android.server.wifi.anqp.HSWanMetricsElement; 7import com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement; 8import com.android.server.wifi.hotspot2.pps.HomeSP; 9 10import java.util.EnumMap; 11import java.util.HashMap; 12import java.util.Map; 13import static com.android.server.wifi.anqp.Constants.ANQPElementType; 14import static com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement.IPv4Availability; 15import static com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement.IPv6Availability; 16 17public class PasspointMatchInfo implements Comparable<PasspointMatchInfo> { 18 private final PasspointMatch mPasspointMatch; 19 private final NetworkDetail mNetworkDetail; 20 private final HomeSP mHomeSP; 21 22 private static final Map<NetworkDetail.Ant, Integer> sAntScores = new HashMap<>(); 23 24 static { 25 sAntScores.put(NetworkDetail.Ant.FreePublic, 7); 26 sAntScores.put(NetworkDetail.Ant.ChargeablePublic, 6); 27 sAntScores.put(NetworkDetail.Ant.PrivateWithGuest, 5); 28 sAntScores.put(NetworkDetail.Ant.Private, 4); 29 sAntScores.put(NetworkDetail.Ant.Personal, 3); 30 sAntScores.put(NetworkDetail.Ant.EmergencyOnly, 2); 31 sAntScores.put(NetworkDetail.Ant.Wildcard, 1); 32 sAntScores.put(NetworkDetail.Ant.TestOrExperimental, 0); 33 } 34 35 public PasspointMatchInfo(PasspointMatch passpointMatch, 36 NetworkDetail networkDetail, HomeSP homeSP) { 37 mPasspointMatch = passpointMatch; 38 mNetworkDetail = networkDetail; 39 mHomeSP = homeSP; 40 } 41 42 public PasspointMatch getPasspointMatch() { 43 return mPasspointMatch; 44 } 45 46 public NetworkDetail getNetworkDetail() { 47 return mNetworkDetail; 48 } 49 50 public HomeSP getHomeSP() { 51 return mHomeSP; 52 } 53 54 @Override 55 public int compareTo(PasspointMatchInfo that) { 56 if (getPasspointMatch() != that.getPasspointMatch()) { 57 return getPasspointMatch().compareTo(that.getPasspointMatch()); 58 } 59 60 // IP Address Type Availability (802.11) 61 62 NetworkDetail n1 = getNetworkDetail(); 63 NetworkDetail n2 = that.getNetworkDetail(); 64 65 if (n1.isInternet() != n2.isInternet()) { 66 return n1.isInternet() ? 1 : -1; 67 } 68 69 if (n1.hasInterworking() && n2.hasInterworking() && n1.getAnt() != n2.getAnt()) { 70 int an1 = sAntScores.get(n1.getAnt()); 71 int an2 = sAntScores.get(n2.getAnt()); 72 return an1 - an2; 73 } 74 75 long score1 = n1.getCapacity() * n1.getChannelUtilization() * n1.getStationCount(); 76 long score2 = n2.getCapacity() * n2.getChannelUtilization() * n2.getStationCount(); 77 78 if (score1 != score2) { 79 return score1 < score2 ? 1 : -1; 80 } 81 82 int comp = subCompare(n1.getANQPElements(), n2.getANQPElements()); 83 if (comp != 0) { 84 return comp; 85 } 86 87 return Utils.compare(n1.getHSRelease(), n2.getHSRelease()); 88 } 89 90 private static final Map<IPv4Availability, Integer> sIP4Scores = 91 new EnumMap<>(IPv4Availability.class); 92 private static final Map<IPv6Availability, Integer> sIP6Scores = 93 new EnumMap<>(IPv6Availability.class); 94 95 private static final Map<Integer, Map<Integer, Integer>> sPortScores = new HashMap<>(); 96 97 private static final int IPPROTO_ICMP = 1; 98 private static final int IPPROTO_TCP = 6; 99 private static final int IPPROTO_UDP = 17; 100 private static final int IPPROTO_ESP = 50; 101 102 static { 103 sIP4Scores.put(IPv4Availability.NotAvailable, 0); 104 sIP4Scores.put(IPv4Availability.PortRestricted, 1); 105 sIP4Scores.put(IPv4Availability.PortRestrictedAndSingleNAT, 1); 106 sIP4Scores.put(IPv4Availability.PortRestrictedAndDoubleNAT, 1); 107 sIP4Scores.put(IPv4Availability.Unknown, 1); 108 sIP4Scores.put(IPv4Availability.Public, 2); 109 sIP4Scores.put(IPv4Availability.SingleNAT, 2); 110 sIP4Scores.put(IPv4Availability.DoubleNAT, 2); 111 112 sIP6Scores.put(IPv6Availability.NotAvailable, 0); 113 sIP6Scores.put(IPv6Availability.Reserved, 1); 114 sIP6Scores.put(IPv6Availability.Unknown, 1); 115 sIP6Scores.put(IPv6Availability.Available, 2); 116 117 Map<Integer, Integer> tcpMap = new HashMap<>(); 118 tcpMap.put(20, 1); 119 tcpMap.put(21, 1); 120 tcpMap.put(22, 3); 121 tcpMap.put(23, 2); 122 tcpMap.put(25, 8); 123 tcpMap.put(26, 8); 124 tcpMap.put(53, 3); 125 tcpMap.put(80, 10); 126 tcpMap.put(110, 6); 127 tcpMap.put(143, 6); 128 tcpMap.put(443, 10); 129 tcpMap.put(993, 6); 130 tcpMap.put(1723, 7); 131 132 Map<Integer, Integer> udpMap = new HashMap<>(); 133 udpMap.put(53, 10); 134 udpMap.put(500, 7); 135 udpMap.put(5060, 10); 136 udpMap.put(4500, 4); 137 138 sPortScores.put(IPPROTO_TCP, tcpMap); 139 sPortScores.put(IPPROTO_UDP, udpMap); 140 } 141 142 private int subCompare(Map<Constants.ANQPElementType, ANQPElement> anqp1, 143 Map<Constants.ANQPElementType, ANQPElement> anqp2) { 144 if (anqp1 == null || anqp2 == null) { 145 return 0; 146 } 147 148 int cmp; 149 150 HSWanMetricsElement w1 = (HSWanMetricsElement) anqp1.get(ANQPElementType.HSWANMetrics); 151 HSWanMetricsElement w2 = (HSWanMetricsElement) anqp2.get(ANQPElementType.HSWANMetrics); 152 if (w1 != null && w2 != null) { 153 154 boolean u1 = w1.getStatus() == HSWanMetricsElement.LinkStatus.Up; 155 boolean u2 = w2.getStatus() == HSWanMetricsElement.LinkStatus.Up; 156 cmp = Boolean.compare(u1, u2); 157 if (cmp != 0) { 158 return cmp; 159 } 160 161 cmp = Boolean.compare(w1.isCapped(), w2.isCapped()); 162 if (cmp != 0) { 163 return cmp; 164 } 165 166 long bw1 = (w1.getDlSpeed() * (long)w1.getDlLoad()) * 8 + 167 (w1.getUlSpeed() * (long)w1.getUlLoad()) * 2; 168 long bw2 = (w2.getDlSpeed() * (long)w2.getDlLoad()) * 8 + 169 (w2.getUlSpeed() * (long)w2.getUlLoad()) * 2; 170 cmp = Long.compare(bw1, bw2); 171 if (cmp != 0) { 172 return cmp; 173 } 174 } 175 176 IPAddressTypeAvailabilityElement a1 = 177 (IPAddressTypeAvailabilityElement)anqp1.get(ANQPElementType.ANQPIPAddrAvailability); 178 IPAddressTypeAvailabilityElement a2 = 179 (IPAddressTypeAvailabilityElement)anqp2.get(ANQPElementType.ANQPIPAddrAvailability); 180 if (a1 != null && a2 != null) { 181 Integer as14 = sIP4Scores.get(a1.getV4Availability()); 182 Integer as16 = sIP6Scores.get(a1.getV6Availability()); 183 Integer as24 = sIP4Scores.get(a2.getV4Availability()); 184 Integer as26 = sIP6Scores.get(a2.getV6Availability()); 185 as14 = as14 != null ? as14 : 1; 186 as16 = as16 != null ? as16 : 1; 187 as24 = as24 != null ? as24 : 1; 188 as26 = as26 != null ? as26 : 1; 189 // Is IPv4 twice as important as IPv6??? 190 int s1 = as14 * 2 + as16; 191 int s2 = as24 * 2 + as26; 192 cmp = Integer.compare(s1, s2); 193 if (cmp != 0) { 194 return cmp; 195 } 196 } 197 198 HSConnectionCapabilityElement cc1 = 199 (HSConnectionCapabilityElement) anqp1.get(ANQPElementType.HSConnCapability); 200 HSConnectionCapabilityElement cc2 = 201 (HSConnectionCapabilityElement) anqp2.get(ANQPElementType.HSConnCapability); 202 203 if (cc1 != null && cc2 != null) { 204 cmp = Integer.compare(protoScore(cc1), protoScore(cc2)); 205 if (cmp != 0) { 206 return cmp; 207 } 208 } 209 210 return 0; 211 } 212 213 private static int protoScore(HSConnectionCapabilityElement cce) { 214 int score = 0; 215 for (HSConnectionCapabilityElement.ProtocolTuple tuple : cce.getStatusList()) { 216 int sign = tuple.getStatus() == HSConnectionCapabilityElement.ProtoStatus.Open ? 217 1 : -1; 218 219 int elementScore = 1; 220 if (tuple.getProtocol() == IPPROTO_ICMP) { 221 elementScore = 1; 222 } 223 else if (tuple.getProtocol() == IPPROTO_ESP) { 224 elementScore = 5; 225 } 226 else { 227 Map<Integer, Integer> protoMap = sPortScores.get(tuple.getProtocol()); 228 if (protoMap != null) { 229 Integer portScore = protoMap.get(tuple.getPort()); 230 elementScore = portScore != null ? portScore : 0; 231 } 232 } 233 score += elementScore * sign; 234 } 235 return score; 236 } 237 238 @Override 239 public boolean equals(Object thatObject) { 240 if (this == thatObject) { 241 return true; 242 } 243 if (thatObject == null || getClass() != thatObject.getClass()) { 244 return false; 245 } 246 247 PasspointMatchInfo that = (PasspointMatchInfo)thatObject; 248 249 return getNetworkDetail().equals(that.getNetworkDetail()) && 250 getHomeSP().equals(that.getHomeSP()) && 251 getPasspointMatch().equals(that.getPasspointMatch()); 252 } 253 254 @Override 255 public int hashCode() { 256 int result = mPasspointMatch != null ? mPasspointMatch.hashCode() : 0; 257 result = 31 * result + mNetworkDetail.hashCode(); 258 result = 31 * result + (mHomeSP != null ? mHomeSP.hashCode() : 0); 259 return result; 260 } 261 262 @Override 263 public String toString() { 264 return "PasspointMatchInfo{" + 265 ", mPasspointMatch=" + mPasspointMatch + 266 ", mNetworkInfo=" + mNetworkDetail.getSSID() + 267 ", mHomeSP=" + mHomeSP.getFQDN() + 268 '}'; 269 } 270} 271