Home | History | Annotate | Download | only in hotspot2
      1 package com.android.server.wifi.hotspot2;
      2 
      3 import com.android.server.wifi.ScanDetail;
      4 import com.android.server.wifi.anqp.ANQPElement;
      5 import com.android.server.wifi.anqp.HSConnectionCapabilityElement;
      6 import com.android.server.wifi.anqp.HSWanMetricsElement;
      7 import com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement;
      8 import com.android.server.wifi.hotspot2.pps.HomeSP;
      9 
     10 import java.util.EnumMap;
     11 import java.util.HashMap;
     12 import java.util.Map;
     13 
     14 import static com.android.server.wifi.anqp.Constants.ANQPElementType;
     15 import static com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement.IPv4Availability;
     16 import static com.android.server.wifi.anqp.IPAddressTypeAvailabilityElement.IPv6Availability;
     17 
     18 public class PasspointMatchInfo implements Comparable<PasspointMatchInfo> {
     19     private final PasspointMatch mPasspointMatch;
     20     private final ScanDetail mScanDetail;
     21     private final HomeSP mHomeSP;
     22     private final int mScore;
     23 
     24     private static final Map<IPv4Availability, Integer> sIP4Scores =
     25             new EnumMap<>(IPv4Availability.class);
     26     private static final Map<IPv6Availability, Integer> sIP6Scores =
     27             new EnumMap<>(IPv6Availability.class);
     28 
     29     private static final Map<Integer, Map<Integer, Integer>> sPortScores = new HashMap<>();
     30 
     31     private static final int IPPROTO_ICMP = 1;
     32     private static final int IPPROTO_TCP = 6;
     33     private static final int IPPROTO_UDP = 17;
     34     private static final int IPPROTO_ESP = 50;
     35     private static final Map<NetworkDetail.Ant, Integer> sAntScores = new HashMap<>();
     36 
     37     static {
     38         // These are all arbitrarily chosen scores, subject to tuning.
     39 
     40         sAntScores.put(NetworkDetail.Ant.FreePublic, 4);
     41         sAntScores.put(NetworkDetail.Ant.ChargeablePublic, 4);
     42         sAntScores.put(NetworkDetail.Ant.PrivateWithGuest, 4);
     43         sAntScores.put(NetworkDetail.Ant.Private, 4);
     44         sAntScores.put(NetworkDetail.Ant.Personal, 2);
     45         sAntScores.put(NetworkDetail.Ant.EmergencyOnly, 2);
     46         sAntScores.put(NetworkDetail.Ant.Wildcard, 1);
     47         sAntScores.put(NetworkDetail.Ant.TestOrExperimental, 0);
     48 
     49         sIP4Scores.put(IPv4Availability.NotAvailable, 0);
     50         sIP4Scores.put(IPv4Availability.PortRestricted, 1);
     51         sIP4Scores.put(IPv4Availability.PortRestrictedAndSingleNAT, 1);
     52         sIP4Scores.put(IPv4Availability.PortRestrictedAndDoubleNAT, 1);
     53         sIP4Scores.put(IPv4Availability.Unknown, 1);
     54         sIP4Scores.put(IPv4Availability.Public, 2);
     55         sIP4Scores.put(IPv4Availability.SingleNAT, 2);
     56         sIP4Scores.put(IPv4Availability.DoubleNAT, 2);
     57 
     58         sIP6Scores.put(IPv6Availability.NotAvailable, 0);
     59         sIP6Scores.put(IPv6Availability.Reserved, 1);
     60         sIP6Scores.put(IPv6Availability.Unknown, 1);
     61         sIP6Scores.put(IPv6Availability.Available, 2);
     62 
     63         Map<Integer, Integer> tcpMap = new HashMap<>();
     64         tcpMap.put(20, 1);
     65         tcpMap.put(21, 1);
     66         tcpMap.put(22, 3);
     67         tcpMap.put(23, 2);
     68         tcpMap.put(25, 8);
     69         tcpMap.put(26, 8);
     70         tcpMap.put(53, 3);
     71         tcpMap.put(80, 10);
     72         tcpMap.put(110, 6);
     73         tcpMap.put(143, 6);
     74         tcpMap.put(443, 10);
     75         tcpMap.put(993, 6);
     76         tcpMap.put(1723, 7);
     77 
     78         Map<Integer, Integer> udpMap = new HashMap<>();
     79         udpMap.put(53, 10);
     80         udpMap.put(500, 7);
     81         udpMap.put(5060, 10);
     82         udpMap.put(4500, 4);
     83 
     84         sPortScores.put(IPPROTO_TCP, tcpMap);
     85         sPortScores.put(IPPROTO_UDP, udpMap);
     86     }
     87 
     88 
     89     public PasspointMatchInfo(PasspointMatch passpointMatch,
     90                               ScanDetail scanDetail, HomeSP homeSP) {
     91         mPasspointMatch = passpointMatch;
     92         mScanDetail = scanDetail;
     93         mHomeSP = homeSP;
     94 
     95         int score;
     96         if (passpointMatch == PasspointMatch.HomeProvider) {
     97             score = 100;
     98         }
     99         else if (passpointMatch == PasspointMatch.RoamingProvider) {
    100             score = 0;
    101         }
    102         else {
    103             score = -1000;  // Don't expect to see anything not home or roaming.
    104         }
    105 
    106         if (getNetworkDetail().getHSRelease() != null) {
    107             score += getNetworkDetail().getHSRelease() != NetworkDetail.HSRelease.Unknown ? 50 : 0;
    108         }
    109 
    110         if (getNetworkDetail().hasInterworking()) {
    111             score += getNetworkDetail().isInternet() ? 20 : -20;
    112         }
    113 
    114         score += (Math.max(200-getNetworkDetail().getStationCount(), 0) *
    115                 (255-getNetworkDetail().getChannelUtilization()) *
    116                 getNetworkDetail().getCapacity()) >>> 26;
    117                 // Gives a value of 23 max capped at 200 stations and max cap 31250
    118 
    119         if (getNetworkDetail().hasInterworking()) {
    120             score += sAntScores.get(getNetworkDetail().getAnt());
    121         }
    122 
    123         Map<ANQPElementType, ANQPElement> anqp = getNetworkDetail().getANQPElements();
    124 
    125         if (anqp != null) {
    126             HSWanMetricsElement wm = (HSWanMetricsElement) anqp.get(ANQPElementType.HSWANMetrics);
    127 
    128             if (wm != null) {
    129                 if (wm.getStatus() != HSWanMetricsElement.LinkStatus.Up || wm.isCapped()) {
    130                     score -= 1000;
    131                 } else {
    132                     long scaledSpeed =
    133                             wm.getDlSpeed() * (255 - wm.getDlLoad()) * 8 +
    134                                     wm.getUlSpeed() * (255 - wm.getUlLoad()) * 2;
    135                     score += Math.min(scaledSpeed, 255000000L) >>> 23;
    136                     // Max value is 30 capped at 100Mb/s
    137                 }
    138             }
    139 
    140             IPAddressTypeAvailabilityElement ipa =
    141                     (IPAddressTypeAvailabilityElement) anqp.get(ANQPElementType.ANQPIPAddrAvailability);
    142 
    143             if (ipa != null) {
    144                 Integer as14 = sIP4Scores.get(ipa.getV4Availability());
    145                 Integer as16 = sIP6Scores.get(ipa.getV6Availability());
    146                 as14 = as14 != null ? as14 : 1;
    147                 as16 = as16 != null ? as16 : 1;
    148                 // Is IPv4 twice as important as IPv6???
    149                 score += as14 * 2 + as16;
    150             }
    151 
    152             HSConnectionCapabilityElement cce =
    153                     (HSConnectionCapabilityElement) anqp.get(ANQPElementType.HSConnCapability);
    154 
    155             if (cce != null) {
    156                 score = Math.min(Math.max(protoScore(cce) >> 3, -10), 10);
    157             }
    158         }
    159 
    160         mScore = score;
    161     }
    162 
    163     public PasspointMatch getPasspointMatch() {
    164         return mPasspointMatch;
    165     }
    166 
    167     public ScanDetail getScanDetail() {
    168         return mScanDetail;
    169     }
    170 
    171     public NetworkDetail getNetworkDetail() {
    172         return mScanDetail.getNetworkDetail();
    173     }
    174 
    175 
    176     public HomeSP getHomeSP() {
    177         return mHomeSP;
    178     }
    179 
    180     public int getScore() {
    181         return mScore;
    182     }
    183 
    184     @Override
    185     public int compareTo(PasspointMatchInfo that) {
    186         return getScore() - that.getScore();
    187     }
    188 
    189     private static int protoScore(HSConnectionCapabilityElement cce) {
    190         int score = 0;
    191         for (HSConnectionCapabilityElement.ProtocolTuple tuple : cce.getStatusList()) {
    192             int sign = tuple.getStatus() == HSConnectionCapabilityElement.ProtoStatus.Open ?
    193                     1 : -1;
    194 
    195             int elementScore = 1;
    196             if (tuple.getProtocol() == IPPROTO_ICMP) {
    197                 elementScore = 1;
    198             }
    199             else if (tuple.getProtocol() == IPPROTO_ESP) {
    200                 elementScore = 5;
    201             }
    202             else {
    203                 Map<Integer, Integer> protoMap = sPortScores.get(tuple.getProtocol());
    204                 if (protoMap != null) {
    205                     Integer portScore = protoMap.get(tuple.getPort());
    206                     elementScore = portScore != null ? portScore : 0;
    207                 }
    208             }
    209             score += elementScore * sign;
    210         }
    211         return score;
    212     }
    213 
    214     @Override
    215     public boolean equals(Object thatObject) {
    216         if (this == thatObject) {
    217             return true;
    218         }
    219         if (thatObject == null || getClass() != thatObject.getClass()) {
    220             return false;
    221         }
    222 
    223         PasspointMatchInfo that = (PasspointMatchInfo)thatObject;
    224 
    225         return getNetworkDetail().equals(that.getNetworkDetail()) &&
    226                 getHomeSP().equals(that.getHomeSP()) &&
    227                 getPasspointMatch().equals(that.getPasspointMatch());
    228     }
    229 
    230     @Override
    231     public int hashCode() {
    232         int result = mPasspointMatch != null ? mPasspointMatch.hashCode() : 0;
    233         result = 31 * result + getNetworkDetail().hashCode();
    234         result = 31 * result + (mHomeSP != null ? mHomeSP.hashCode() : 0);
    235         return result;
    236     }
    237 
    238     @Override
    239     public String toString() {
    240         return "PasspointMatchInfo{" +
    241                 ", mPasspointMatch=" + mPasspointMatch +
    242                 ", mNetworkInfo=" + getNetworkDetail().getSSID() +
    243                 ", mHomeSP=" + mHomeSP.getFQDN() +
    244                 '}';
    245     }
    246 }
    247