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

Commit 99cfe09f authored by Roshan Pius's avatar Roshan Pius
Browse files

wifi(API): NetworkSpecifier for Wifi NetworkAgent

Create an @hide NetworkSpecifier to use by the Wifi NetworkAgent. This
will be used by connectivity service to match the incoming
NetworkRequest (with WifiNetworkSpecifier) with the NetworkAgent we
created to serve that request.
The WifiNetworkAgentSpecifier will hold the current connected wifi
network configuration which will be used to pattern match the
WifiNetworkSpecifier from NetworkRequest's.

Also, added a @hide helper method in MacAddress to help with matching
bssid pattern.

Bug: 113878056
Test: Unit tests
Change-Id: I9a643f0b914d48ff64104c798ec2869db40cb24b
parent 914a64ec
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -393,4 +393,19 @@ public final class MacAddress implements Parcelable {
        }
        return out;
    }

    /**
     * Checks if this MAC Address matches the provided range.
     *
     * @param baseAddress MacAddress representing the base address to compare with.
     * @param mask MacAddress representing the mask to use during comparison.
     * @return true if this MAC Address matches the given range.
     *
     * @hide
     */
    public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) {
        Preconditions.checkNotNull(baseAddress);
        Preconditions.checkNotNull(mask);
        return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr);
    }
}
+34 −1
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
package android.net;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import android.support.test.filters.SmallTest;
@@ -252,6 +252,39 @@ public class MacAddressTest {
        }
    }

    @Test
    public void testMatches() {
        // match 4 bytes prefix
        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("aa:bb:cc:dd:00:00"),
                MacAddress.fromString("ff:ff:ff:ff:00:00")));

        // match bytes 0,1,2 and 5
        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("aa:bb:cc:00:00:11"),
                MacAddress.fromString("ff:ff:ff:00:00:ff")));

        // match 34 bit prefix
        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("aa:bb:cc:dd:c0:00"),
                MacAddress.fromString("ff:ff:ff:ff:c0:00")));

        // fail to match 36 bit prefix
        assertFalse(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("aa:bb:cc:dd:40:00"),
                MacAddress.fromString("ff:ff:ff:ff:f0:00")));

        // match all 6 bytes
        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("aa:bb:cc:dd:ee:11"),
                MacAddress.fromString("ff:ff:ff:ff:ff:ff")));

        // match none of 6 bytes
        assertTrue(MacAddress.fromString("aa:bb:cc:dd:ee:11").matches(
                MacAddress.fromString("00:00:00:00:00:00"),
                MacAddress.fromString("00:00:00:00:00:00")));
    }

    static byte[] toByteArray(int... in) {
        byte[] out = new byte[in.length];
        for (int i = 0; i < in.length; i++) {
+187 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net.wifi;

import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.MacAddress;
import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkAgent;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;

import java.util.Objects;

/**
 * Network specifier object used by wifi's {@link android.net.NetworkAgent}.
 * @hide
 */
public final class WifiNetworkAgentSpecifier extends NetworkSpecifier implements Parcelable {
    /**
     * Security credentials for the currently connected network.
     */
    private final WifiConfiguration mWifiConfiguration;

    /**
     * The UID of the app that requested a specific wifi network using {@link WifiNetworkSpecifier}.
     *
     * Will only be filled when the device connects to a wifi network as a result of a
     * {@link NetworkRequest} with {@link WifiNetworkSpecifier}. Will be set to -1 if the device
     * auto-connected to a wifi network.
     */
    private final int mOriginalRequestorUid;

    public WifiNetworkAgentSpecifier(@NonNull WifiConfiguration wifiConfiguration,
                                     int originalRequestorUid) {
        checkNotNull(wifiConfiguration);

        mWifiConfiguration = wifiConfiguration;
        mOriginalRequestorUid = originalRequestorUid;
    }

    /**
     * @hide
     */
    public static final Creator<WifiNetworkAgentSpecifier> CREATOR =
            new Creator<WifiNetworkAgentSpecifier>() {
                @Override
                public WifiNetworkAgentSpecifier createFromParcel(@NonNull Parcel in) {
                    WifiConfiguration wifiConfiguration = in.readParcelable(null);
                    int originalRequestorUid = in.readInt();
                    return new WifiNetworkAgentSpecifier(wifiConfiguration, originalRequestorUid);
                }

                @Override
                public WifiNetworkAgentSpecifier[] newArray(int size) {
                    return new WifiNetworkAgentSpecifier[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeParcelable(mWifiConfiguration, flags);
        dest.writeInt(mOriginalRequestorUid);
    }

    @Override
    public boolean satisfiedBy(@Nullable NetworkSpecifier other) {
        if (this == other) {
            return true;
        }
        // Any generic requests should be satisifed by a specific wifi network.
        if (other == null || other instanceof MatchAllNetworkSpecifier) {
            return true;
        }
        if (other instanceof WifiNetworkSpecifier) {
            return satisfiesNetworkSpecifier((WifiNetworkSpecifier) other);
        }
        if (other instanceof WifiNetworkAgentSpecifier) {
            throw new IllegalStateException("WifiNetworkAgentSpecifier instances should never be "
                    + "compared");
        }
        return false;
    }

    /**
     * Match {@link WifiNetworkSpecifier} in app's {@link NetworkRequest} with the
     * {@link WifiNetworkAgentSpecifier} in wifi platform's {@link NetworkAgent}.
     */
    public boolean satisfiesNetworkSpecifier(@NonNull WifiNetworkSpecifier ns) {
        // None of these should be null by construction.
        // {@link WifiNetworkConfigBuilder} enforces non-null in {@link WifiNetworkSpecifier}.
        // {@link WifiNetworkFactory} ensures non-null in {@link WifiNetworkAgentSpecifier}.
        checkNotNull(ns);
        checkNotNull(ns.ssidPatternMatcher);
        checkNotNull(ns.bssidPatternMatcher);
        checkNotNull(ns.wifiConfiguration.allowedKeyManagement);
        checkNotNull(this.mWifiConfiguration.SSID);
        checkNotNull(this.mWifiConfiguration.BSSID);
        checkNotNull(this.mWifiConfiguration.allowedKeyManagement);

        final String ssidWithQuotes = this.mWifiConfiguration.SSID;
        checkState(ssidWithQuotes.startsWith("\"") && ssidWithQuotes.endsWith("\""));
        final String ssidWithoutQuotes = ssidWithQuotes.substring(1, ssidWithQuotes.length() - 1);
        if (!ns.ssidPatternMatcher.match(ssidWithoutQuotes)) {
            return false;
        }
        final MacAddress bssid = MacAddress.fromString(this.mWifiConfiguration.BSSID);
        final MacAddress matchBaseAddress = ns.bssidPatternMatcher.first;
        final MacAddress matchMask = ns.bssidPatternMatcher.second;
        if (!bssid.matches(matchBaseAddress, matchMask))  {
            return false;
        }
        if (!ns.wifiConfiguration.allowedKeyManagement.equals(
                this.mWifiConfiguration.allowedKeyManagement)) {
            return false;
        }
        if (ns.requestorUid != this.mOriginalRequestorUid) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return Objects.hash(
                mWifiConfiguration.SSID,
                mWifiConfiguration.BSSID,
                mWifiConfiguration.allowedKeyManagement,
                mOriginalRequestorUid);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof WifiNetworkAgentSpecifier)) {
            return false;
        }
        WifiNetworkAgentSpecifier lhs = (WifiNetworkAgentSpecifier) obj;
        return Objects.equals(this.mWifiConfiguration.SSID, lhs.mWifiConfiguration.SSID)
                && Objects.equals(this.mWifiConfiguration.BSSID, lhs.mWifiConfiguration.BSSID)
                && Objects.equals(this.mWifiConfiguration.allowedKeyManagement,
                    lhs.mWifiConfiguration.allowedKeyManagement)
                && mOriginalRequestorUid == lhs.mOriginalRequestorUid;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("WifiNetworkAgentSpecifier [");
        sb.append(", WifiConfiguration=").append(
                mWifiConfiguration == null ? null : mWifiConfiguration.configKey())
                .append(", mOriginalRequestorUid=").append(mOriginalRequestorUid)
                .append("]");
        return sb.toString();
    }

    @Override
    public void assertValidFromUid(int requestorUid) {
        throw new IllegalStateException("WifiNetworkAgentSpecifier should never be used "
                + "for requests.");
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -121,6 +121,9 @@ public final class WifiNetworkSpecifier extends NetworkSpecifier implements Parc
        if (other == null || other instanceof MatchAllNetworkSpecifier) {
            return true;
        }
        if (other instanceof WifiNetworkAgentSpecifier) {
            return ((WifiNetworkAgentSpecifier) other).satisfiesNetworkSpecifier(this);
        }
        // Specific requests are checked for equality although testing for equality of 2 patterns do
        // not make much sense!
        return equals(other);
+453 −0

File added.

Preview size limit exceeded, changes collapsed.