Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3562952f authored by lesl's avatar lesl Committed by Les Lee
Browse files

softap: Add SAE and SAE transition mode in configuration

Bug: 142752869
Test: atest frameworks/base/wifi/tests/
Change-Id: I2eac1b7291554cd69db9833d494ba741a65d86c3
parent 005c68cf
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -5739,6 +5739,7 @@ package android.net.wifi {
    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApCapability> CREATOR;
    field public static final int SOFTAP_FEATURE_ACS_OFFLOAD = 1; // 0x1
    field public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 2; // 0x2
    field public static final int SOFTAP_FEATURE_WPA3_SAE = 4; // 0x4
  }
  public final class SoftApConfiguration implements android.os.Parcelable {
@@ -5747,6 +5748,7 @@ package android.net.wifi {
    method @Nullable public android.net.MacAddress getBssid();
    method public int getChannel();
    method public int getMaxNumberOfClients();
    method @Nullable public String getPassphrase();
    method public int getSecurityType();
    method @Nullable public String getSsid();
    method @Nullable public String getWpa2Passphrase();
@@ -5759,6 +5761,8 @@ package android.net.wifi {
    field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.SoftApConfiguration> CREATOR;
    field public static final int SECURITY_TYPE_OPEN = 0; // 0x0
    field public static final int SECURITY_TYPE_WPA2_PSK = 1; // 0x1
    field public static final int SECURITY_TYPE_WPA3_SAE = 3; // 0x3
    field public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2; // 0x2
  }
  public static final class SoftApConfiguration.Builder {
@@ -5770,6 +5774,7 @@ package android.net.wifi {
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(int);
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
    method @NonNull public android.net.wifi.SoftApConfiguration.Builder setWpa2Passphrase(@Nullable String);
  }
+9 −0
Original line number Diff line number Diff line
@@ -61,11 +61,20 @@ public final class SoftApCapability implements Parcelable {
     */
    public static final int SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT = 1 << 1;


    /**
     * Support for WPA3 Simultaneous Authentication of Equals (WPA3-SAE).
     *
     * flag when {@link config_wifi_softap_sae_supported)} is true.
     */
    public static final int SOFTAP_FEATURE_WPA3_SAE = 1 << 2;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, prefix = { "SOFTAP_FEATURE_" }, value = {
            SOFTAP_FEATURE_ACS_OFFLOAD,
            SOFTAP_FEATURE_CLIENT_FORCE_DISCONNECT,
            SOFTAP_FEATURE_WPA3_SAE,
    })
    public @interface HotspotFeatures {}

+87 −33
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

import java.lang.annotation.Retention;
@@ -55,6 +56,11 @@ import java.util.concurrent.Executor;
@SystemApi
public final class SoftApConfiguration implements Parcelable {

    @VisibleForTesting
    static final int PSK_MIN_LEN = 8;
    @VisibleForTesting
    static final int PSK_MAX_LEN = 63;

    /**
     * 2GHz band.
     * @hide
@@ -142,9 +148,10 @@ public final class SoftApConfiguration implements Parcelable {
    private final @Nullable MacAddress mBssid;

    /**
     * Pre-shared key for WPA2-PSK encryption (non-null enables WPA2-PSK).
     * Pre-shared key for WPA2-PSK or WPA3-SAE-Transition or WPA3-SAE encryption which depends on
     * the security type.
     */
    private final @Nullable String mWpa2Passphrase;
    private final @Nullable String mPassphrase;

    /**
     * This is a network that does not broadcast its SSID, so an
@@ -185,21 +192,31 @@ public final class SoftApConfiguration implements Parcelable {
    @SystemApi
    public static final int SECURITY_TYPE_WPA2_PSK = 1;

    /** @hide */
    @SystemApi
    public static final int SECURITY_TYPE_WPA3_SAE_TRANSITION = 2;

    /** @hide */
    @SystemApi
    public static final int SECURITY_TYPE_WPA3_SAE = 3;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = { "SECURITY_TYPE" }, value = {
    @IntDef(prefix = { "SECURITY_TYPE_" }, value = {
        SECURITY_TYPE_OPEN,
        SECURITY_TYPE_WPA2_PSK,
        SECURITY_TYPE_WPA3_SAE_TRANSITION,
        SECURITY_TYPE_WPA3_SAE,
    })
    public @interface SecurityType {}

    /** Private constructor for Builder and Parcelable implementation. */
    private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
            @Nullable String wpa2Passphrase, boolean hiddenSsid, @BandType int band, int channel,
            @Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
            @SecurityType int securityType, int maxNumberOfClients) {
        mSsid = ssid;
        mBssid = bssid;
        mWpa2Passphrase = wpa2Passphrase;
        mPassphrase = passphrase;
        mHiddenSsid = hiddenSsid;
        mBand = band;
        mChannel = channel;
@@ -218,7 +235,7 @@ public final class SoftApConfiguration implements Parcelable {
        SoftApConfiguration other = (SoftApConfiguration) otherObj;
        return Objects.equals(mSsid, other.mSsid)
                && Objects.equals(mBssid, other.mBssid)
                && Objects.equals(mWpa2Passphrase, other.mWpa2Passphrase)
                && Objects.equals(mPassphrase, other.mPassphrase)
                && mHiddenSsid == other.mHiddenSsid
                && mBand == other.mBand
                && mChannel == other.mChannel
@@ -228,7 +245,7 @@ public final class SoftApConfiguration implements Parcelable {

    @Override
    public int hashCode() {
        return Objects.hash(mSsid, mBssid, mWpa2Passphrase, mHiddenSsid,
        return Objects.hash(mSsid, mBssid, mPassphrase, mHiddenSsid,
                mBand, mChannel, mSecurityType, mMaxNumberOfClients);
    }

@@ -237,8 +254,8 @@ public final class SoftApConfiguration implements Parcelable {
        StringBuilder sbuf = new StringBuilder();
        sbuf.append("ssid=").append(mSsid);
        if (mBssid != null) sbuf.append(" \n bssid=").append(mBssid.toString());
        sbuf.append(" \n Wpa2Passphrase =").append(
                TextUtils.isEmpty(mWpa2Passphrase) ? "<empty>" : "<non-empty>");
        sbuf.append(" \n Passphrase =").append(
                TextUtils.isEmpty(mPassphrase) ? "<empty>" : "<non-empty>");
        sbuf.append(" \n HiddenSsid =").append(mHiddenSsid);
        sbuf.append(" \n Band =").append(mBand);
        sbuf.append(" \n Channel =").append(mChannel);
@@ -251,7 +268,7 @@ public final class SoftApConfiguration implements Parcelable {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeString(mSsid);
        dest.writeParcelable(mBssid, flags);
        dest.writeString(mWpa2Passphrase);
        dest.writeString(mPassphrase);
        dest.writeBoolean(mHiddenSsid);
        dest.writeInt(mBand);
        dest.writeInt(mChannel);
@@ -299,13 +316,26 @@ public final class SoftApConfiguration implements Parcelable {
        return mBssid;
    }

    // TODO: Remove it after update the caller
    /**
     * Returns String set to be passphrase for the WPA2-PSK AP.
     * {@link Builder#setWpa2Passphrase(String)}.
     * {@link #setWpa2Passphrase(String)}.
     */
    @Nullable
    public String getWpa2Passphrase() {
        return mWpa2Passphrase;
        if (mSecurityType == SECURITY_TYPE_WPA2_PSK) {
            return mPassphrase;
        }
        return null;
    }

    /**
     * Returns String set to be passphrase for current AP.
     * {@link #setPassphrase(String, @SecurityType int)}.
     */
    @Nullable
    public String getPassphrase() {
        return mPassphrase;
    }

    /**
@@ -360,23 +390,12 @@ public final class SoftApConfiguration implements Parcelable {
    public static final class Builder {
        private String mSsid;
        private MacAddress mBssid;
        private String mWpa2Passphrase;
        private String mPassphrase;
        private boolean mHiddenSsid;
        private int mBand;
        private int mChannel;
        private int mMaxNumberOfClients;

        private int setSecurityType() {
            int securityType = SECURITY_TYPE_OPEN;
            if (!TextUtils.isEmpty(mWpa2Passphrase)) { // WPA2-PSK network.
                securityType = SECURITY_TYPE_WPA2_PSK;
            }
            return securityType;
        }

        private void clearAllPassphrase() {
            mWpa2Passphrase = null;
        }
        private int mSecurityType;

        /**
         * Constructs a Builder with default values (see {@link Builder}).
@@ -384,11 +403,12 @@ public final class SoftApConfiguration implements Parcelable {
        public Builder() {
            mSsid = null;
            mBssid = null;
            mWpa2Passphrase = null;
            mPassphrase = null;
            mHiddenSsid = false;
            mBand = BAND_2GHZ;
            mChannel = 0;
            mMaxNumberOfClients = 0;
            mSecurityType = SECURITY_TYPE_OPEN;
        }

        /**
@@ -399,11 +419,12 @@ public final class SoftApConfiguration implements Parcelable {

            mSsid = other.mSsid;
            mBssid = other.mBssid;
            mWpa2Passphrase = other.mWpa2Passphrase;
            mPassphrase = other.mPassphrase;
            mHiddenSsid = other.mHiddenSsid;
            mBand = other.mBand;
            mChannel = other.mChannel;
            mMaxNumberOfClients = other.mMaxNumberOfClients;
            mSecurityType = other.mSecurityType;
        }

        /**
@@ -413,8 +434,8 @@ public final class SoftApConfiguration implements Parcelable {
         */
        @NonNull
        public SoftApConfiguration build() {
            return new SoftApConfiguration(mSsid, mBssid, mWpa2Passphrase,
                mHiddenSsid, mBand, mChannel, setSecurityType(), mMaxNumberOfClients);
            return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
                mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients);
        }

        /**
@@ -461,6 +482,7 @@ public final class SoftApConfiguration implements Parcelable {
            return this;
        }

        // TODO: Remove it after update the caller
        /**
         * Specifies that this AP should use WPA2-PSK with the given ASCII WPA2 passphrase.
         * When set to null, an open network is created.
@@ -473,15 +495,47 @@ public final class SoftApConfiguration implements Parcelable {
         */
        @NonNull
        public Builder setWpa2Passphrase(@Nullable String passphrase) {
            return setPassphrase(passphrase, SECURITY_TYPE_WPA2_PSK);
        }

        /**
         * Specifies that this AP should use specific security type with the given ASCII passphrase.
         *
         * @param securityType one of the security types from {@link @SecurityType}.
         * @param passphrase The passphrase to use for sepcific {@link @SecurityType} configuration
         * or null with {@link @SecurityType#SECURITY_TYPE_OPEN}.
         *
         * @return Builder for chaining.
         * @throws IllegalArgumentException when the passphrase length is invalid and
         *         {@code securityType} is not {@link @SecurityType#SECURITY_TYPE_OPEN}
         *         or non-null passphrase and {@code securityType} is
         *         {@link @SecurityType#SECURITY_TYPE_OPEN}.
         */
        @NonNull
        public Builder setPassphrase(@Nullable String passphrase, @SecurityType int securityType) {
            if (securityType == SECURITY_TYPE_OPEN) {
                if (passphrase != null) {
                    throw new IllegalArgumentException(
                            "passphrase should be null when security type is open");
                }
            } else {
                Preconditions.checkStringNotEmpty(passphrase);
                final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
                if (!asciiEncoder.canEncode(passphrase)) {
                    throw new IllegalArgumentException("passphrase not ASCII encodable");
                }
                Preconditions.checkStringNotEmpty(passphrase);
                if (securityType == SECURITY_TYPE_WPA2_PSK
                        || securityType == SECURITY_TYPE_WPA3_SAE_TRANSITION) {
                    if (passphrase.length() < PSK_MIN_LEN || passphrase.length() > PSK_MAX_LEN) {
                        throw new IllegalArgumentException(
                                "Password size must be at least " + PSK_MIN_LEN
                                + " and no more than " + PSK_MAX_LEN
                                + " for WPA2_PSK and WPA3_SAE_TRANSITION Mode");
                    }
                }
            clearAllPassphrase();
            mWpa2Passphrase = passphrase;
            }
            mSecurityType = securityType;
            mPassphrase = passphrase;
            return this;
        }

+122 −6
Original line number Diff line number Diff line
@@ -25,8 +25,12 @@ import androidx.test.filters.SmallTest;

import org.junit.Test;

import java.util.Random;

@SmallTest
public class SoftApConfigurationTest {
    private static final String TEST_CHAR_SET_AS_STRING = "abcdefghijklmnopqrstuvwxyz0123456789";

    private SoftApConfiguration parcelUnparcel(SoftApConfiguration configIn) {
        Parcel parcel = Parcel.obtain();
        parcel.writeParcelable(configIn, 0);
@@ -37,6 +41,25 @@ public class SoftApConfigurationTest {
        return configOut;
    }

    /**
     * Helper method to generate random string.
     *
     * Note: this method has limited use as a random string generator.
     * The characters used in this method do no not cover all valid inputs.
     * @param length number of characters to generate for the string
     * @return String generated string of random characters
     */
    private String generateRandomString(int length) {
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder(length);
        int index = -1;
        while (stringBuilder.length() < length) {
            index = random.nextInt(TEST_CHAR_SET_AS_STRING.length());
            stringBuilder.append(TEST_CHAR_SET_AS_STRING.charAt(index));
        }
        return stringBuilder.toString();
    }

    @Test
    public void testBasicSettings() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
@@ -45,7 +68,7 @@ public class SoftApConfigurationTest {
                .build();
        assertThat(original.getSsid()).isEqualTo("ssid");
        assertThat(original.getBssid()).isEqualTo(MacAddress.fromString("11:22:33:44:55:66"));
        assertThat(original.getWpa2Passphrase()).isNull();
        assertThat(original.getPassphrase()).isNull();
        assertThat(original.getSecurityType()).isEqualTo(SoftApConfiguration.SECURITY_TYPE_OPEN);
        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
        assertThat(original.getChannel()).isEqualTo(0);
@@ -66,9 +89,9 @@ public class SoftApConfigurationTest {
    @Test
    public void testWpa2() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setWpa2Passphrase("secretsecret")
                .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
                .build();
        assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
        assertThat(original.getPassphrase()).isEqualTo("secretsecret");
        assertThat(original.getSecurityType()).isEqualTo(
                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
@@ -90,13 +113,12 @@ public class SoftApConfigurationTest {
    @Test
    public void testWpa2WithAllFieldCustomized() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setWpa2Passphrase("secretsecret")
                .setBand(SoftApConfiguration.BAND_ANY)
                .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .setMaxNumberOfClients(10)
                .build();
        assertThat(original.getWpa2Passphrase()).isEqualTo("secretsecret");
        assertThat(original.getPassphrase()).isEqualTo("secretsecret");
        assertThat(original.getSecurityType()).isEqualTo(
                SoftApConfiguration.SECURITY_TYPE_WPA2_PSK);
        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
@@ -114,4 +136,98 @@ public class SoftApConfigurationTest {
        assertThat(copy).isEqualTo(original);
        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
    }

    @Test
    public void testWpa3Sae() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase("secretsecret", SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
        assertThat(original.getPassphrase()).isEqualTo("secretsecret");
        assertThat(original.getSecurityType()).isEqualTo(
                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE);
        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
        assertThat(original.getChannel()).isEqualTo(149);
        assertThat(original.isHiddenSsid()).isEqualTo(true);


        SoftApConfiguration unparceled = parcelUnparcel(original);
        assertThat(unparceled).isNotSameAs(original);
        assertThat(unparceled).isEqualTo(original);
        assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());

        SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
        assertThat(copy).isNotSameAs(original);
        assertThat(copy).isEqualTo(original);
        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
    }

    @Test
    public void testWpa3SaeTransition() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase("secretsecret",
                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
        assertThat(original.getSecurityType()).isEqualTo(
                SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION);
        assertThat(original.getPassphrase()).isEqualTo("secretsecret");
        assertThat(original.getBand()).isEqualTo(SoftApConfiguration.BAND_5GHZ);
        assertThat(original.getChannel()).isEqualTo(149);
        assertThat(original.isHiddenSsid()).isEqualTo(true);


        SoftApConfiguration unparceled = parcelUnparcel(original);
        assertThat(unparceled).isNotSameAs(original);
        assertThat(unparceled).isEqualTo(original);
        assertThat(unparceled.hashCode()).isEqualTo(original.hashCode());

        SoftApConfiguration copy = new SoftApConfiguration.Builder(original).build();
        assertThat(copy).isNotSameAs(original);
        assertThat(copy).isEqualTo(original);
        assertThat(copy.hashCode()).isEqualTo(original.hashCode());
    }

    @Test(expected = IllegalArgumentException.class)
    public void testInvalidShortPasswordLengthForWpa2() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
                        SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
    }

    @Test(expected = IllegalArgumentException.class)
    public void testInvalidLongPasswordLengthForWpa2() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
                        SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
    }

    @Test(expected = IllegalArgumentException.class)
    public void testInvalidShortPasswordLengthForWpa3SaeTransition() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MIN_LEN - 1),
                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
    }

    @Test(expected = IllegalArgumentException.class)
    public void testInvalidLongPasswordLengthForWpa3SaeTransition() {
        SoftApConfiguration original = new SoftApConfiguration.Builder()
                .setPassphrase(generateRandomString(SoftApConfiguration.PSK_MAX_LEN + 1),
                        SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION)
                .setChannel(149, SoftApConfiguration.BAND_5GHZ)
                .setHiddenSsid(true)
                .build();
    }

}