package com.android.server.wifi.anqp; import com.android.server.wifi.anqp.eap.EAPMethod; import com.android.server.wifi.hotspot2.AuthMatch; import com.android.server.wifi.hotspot2.Utils; import com.android.server.wifi.hotspot2.pps.Credential; import com.android.server.wifi.hotspot2.pps.DomainMatcher; import java.net.ProtocolException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * The NAI Realm Data ANQP sub-element, IEEE802.11-2012 section 8.4.4.10 figure 8-418 */ public class NAIRealmData { private final List<String> mRealms; private final List<EAPMethod> mEAPMethods; public NAIRealmData(ByteBuffer payload) throws ProtocolException { if (payload.remaining() < 5) { throw new ProtocolException("Runt payload: " + payload.remaining()); } int length = payload.getShort() & Constants.SHORT_MASK; if (length > payload.remaining()) { throw new ProtocolException("Invalid data length: " + length); } boolean utf8 = (payload.get() & 1) == Constants.UTF8_INDICATOR; String realm = Constants.getPrefixedString(payload, 1, utf8 ? StandardCharsets.UTF_8 : StandardCharsets.US_ASCII); String[] realms = realm.split(";"); mRealms = new ArrayList<>(); for (String realmElement : realms) { if (realmElement.length() > 0) { mRealms.add(realmElement); } } int methodCount = payload.get() & Constants.BYTE_MASK; mEAPMethods = new ArrayList<>(methodCount); while (methodCount > 0) { mEAPMethods.add(new EAPMethod(payload)); methodCount--; } } public List<String> getRealms() { return Collections.unmodifiableList(mRealms); } public List<EAPMethod> getEAPMethods() { return Collections.unmodifiableList(mEAPMethods); } public int match(List<String> credLabels, Credential credential) { int realmMatch = AuthMatch.None; if (!mRealms.isEmpty()) { for (String realm : mRealms) { List<String> labels = Utils.splitDomain(realm); if (DomainMatcher.arg2SubdomainOfArg1(credLabels, labels)) { realmMatch = AuthMatch.Realm; break; } } if (realmMatch == AuthMatch.None || mEAPMethods.isEmpty()) { return realmMatch; } // else there is a realm match and one or more EAP methods - check them. } else if (mEAPMethods.isEmpty()) { return AuthMatch.Indeterminate; } int best = AuthMatch.None; for (EAPMethod eapMethod : mEAPMethods) { int match = eapMethod.match(credential) | realmMatch; if (match > best) { best = match; if (best == AuthMatch.Exact) { return best; } } } return best; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" NAI Realm(s)"); for (String realm : mRealms) { sb.append(' ').append(realm); } sb.append('\n'); for (EAPMethod eapMethod : mEAPMethods) { sb.append( " " ).append(eapMethod.toString()); } return sb.toString(); } }