1 package com.android.server.wifi.anqp; 2 3 import com.android.server.wifi.anqp.eap.EAPMethod; 4 import com.android.server.wifi.hotspot2.AuthMatch; 5 import com.android.server.wifi.hotspot2.Utils; 6 import com.android.server.wifi.hotspot2.pps.Credential; 7 import com.android.server.wifi.hotspot2.pps.DomainMatcher; 8 9 import java.net.ProtocolException; 10 import java.nio.ByteBuffer; 11 import java.nio.charset.StandardCharsets; 12 import java.util.ArrayList; 13 import java.util.Collections; 14 import java.util.List; 15 16 /** 17 * The NAI Realm Data ANQP sub-element, IEEE802.11-2012 section 8.4.4.10 figure 8-418 18 */ 19 public class NAIRealmData { 20 private final List<String> mRealms; 21 private final List<EAPMethod> mEAPMethods; 22 23 public NAIRealmData(ByteBuffer payload) throws ProtocolException { 24 if (payload.remaining() < 5) { 25 throw new ProtocolException("Runt payload: " + payload.remaining()); 26 } 27 28 int length = payload.getShort() & Constants.SHORT_MASK; 29 if (length > payload.remaining()) { 30 throw new ProtocolException("Invalid data length: " + length); 31 } 32 boolean utf8 = (payload.get() & 1) == Constants.UTF8_INDICATOR; 33 34 String realm = Constants.getPrefixedString(payload, 1, utf8 ? 35 StandardCharsets.UTF_8 : 36 StandardCharsets.US_ASCII); 37 String[] realms = realm.split(";"); 38 mRealms = new ArrayList<>(); 39 for (String realmElement : realms) { 40 if (realmElement.length() > 0) { 41 mRealms.add(realmElement); 42 } 43 } 44 45 int methodCount = payload.get() & Constants.BYTE_MASK; 46 mEAPMethods = new ArrayList<>(methodCount); 47 while (methodCount > 0) { 48 mEAPMethods.add(new EAPMethod(payload)); 49 methodCount--; 50 } 51 } 52 53 public List<String> getRealms() { 54 return Collections.unmodifiableList(mRealms); 55 } 56 57 public List<EAPMethod> getEAPMethods() { 58 return Collections.unmodifiableList(mEAPMethods); 59 } 60 61 public int match(List<String> credLabels, Credential credential) { 62 int realmMatch = AuthMatch.None; 63 if (!mRealms.isEmpty()) { 64 for (String realm : mRealms) { 65 List<String> labels = Utils.splitDomain(realm); 66 if (DomainMatcher.arg2SubdomainOfArg1(credLabels, labels)) { 67 realmMatch = AuthMatch.Realm; 68 break; 69 } 70 } 71 if (realmMatch == AuthMatch.None || mEAPMethods.isEmpty()) { 72 return realmMatch; 73 } 74 // else there is a realm match and one or more EAP methods - check them. 75 } 76 else if (mEAPMethods.isEmpty()) { 77 return AuthMatch.Indeterminate; 78 } 79 80 int best = AuthMatch.None; 81 for (EAPMethod eapMethod : mEAPMethods) { 82 int match = eapMethod.match(credential) | realmMatch; 83 if (match > best) { 84 best = match; 85 if (best == AuthMatch.Exact) { 86 return best; 87 } 88 } 89 } 90 return best; 91 } 92 93 @Override 94 public String toString() { 95 StringBuilder sb = new StringBuilder(); 96 97 sb.append(" NAI Realm(s)"); 98 for (String realm : mRealms) { 99 sb.append(' ').append(realm); 100 } 101 sb.append('\n'); 102 103 for (EAPMethod eapMethod : mEAPMethods) { 104 sb.append( " " ).append(eapMethod.toString()); 105 } 106 return sb.toString(); 107 } 108 } 109