diff options
Diffstat (limited to 'common/device')
85 files changed, 0 insertions, 13243 deletions
diff --git a/common/device/android/net/NetworkFactory.java b/common/device/android/net/NetworkFactory.java deleted file mode 100644 index 87f6dee6..00000000 --- a/common/device/android/net/NetworkFactory.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import static com.android.modules.utils.build.SdkLevel.isAtLeastS; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.os.Looper; -import android.os.Message; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * A NetworkFactory is an entity that creates NetworkAgent objects. - * The bearers register with ConnectivityService using {@link #register} and - * their factory will start receiving scored NetworkRequests. NetworkRequests - * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by - * overridden function. All of these can be dynamic - changing NetworkCapabilities - * or score forces re-evaluation of all current requests. - * - * If any requests pass the filter some overrideable functions will be called. - * If the bearer only cares about very simple start/stopNetwork callbacks, those - * functions can be overridden. If the bearer needs more interaction, it can - * override addNetworkRequest and removeNetworkRequest which will give it each - * request that passes their current filters. - * - * This class is mostly a shim which delegates to one of two implementations depending - * on the SDK level of the device it's running on. - * - * @hide - **/ -public class NetworkFactory { - static final boolean DBG = true; - static final boolean VDBG = false; - - final NetworkFactoryShim mImpl; - - private final String LOG_TAG; - - // Ideally the filter argument would be non-null, but null has historically meant to see - // no requests and telephony passes null. - public NetworkFactory(Looper looper, Context context, String logTag, - @Nullable final NetworkCapabilities filter) { - LOG_TAG = logTag; - if (isAtLeastS()) { - mImpl = new NetworkFactoryImpl(this, looper, context, filter); - } else { - mImpl = new NetworkFactoryLegacyImpl(this, looper, context, filter); - } - } - - // TODO : these two constants and the method are only used by telephony tests. Replace it in - // the tests and remove them and the associated code. - public static final int CMD_REQUEST_NETWORK = 1; - public static final int CMD_CANCEL_REQUEST = 2; - /** Like Handler#obtainMessage */ - @VisibleForTesting - public Message obtainMessage(final int what, final int arg1, final int arg2, - final @Nullable Object obj) { - return mImpl.obtainMessage(what, arg1, arg2, obj); - } - - // Called by BluetoothNetworkFactory - public final Looper getLooper() { - return mImpl.getLooper(); - } - - // Refcount for simple mode requests - private int mRefCount = 0; - - /* Registers this NetworkFactory with the system. May only be called once per factory. */ - public void register() { - mImpl.register(LOG_TAG); - } - - /** - * Registers this NetworkFactory with the system ignoring the score filter. This will let - * the factory always see all network requests matching its capabilities filter. - * May only be called once per factory. - */ - public void registerIgnoringScore() { - mImpl.registerIgnoringScore(LOG_TAG); - } - - /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ - public void terminate() { - mImpl.terminate(); - } - - protected final void reevaluateAllRequests() { - mImpl.reevaluateAllRequests(); - } - - /** - * Overridable function to provide complex filtering. - * Called for every request every time a new NetworkRequest is seen - * and whenever the filterScore or filterNetworkCapabilities change. - * - * acceptRequest can be overridden to provide complex filter behavior - * for the incoming requests - * - * For output, this class will call {@link #needNetworkFor} and - * {@link #releaseNetworkFor} for every request that passes the filters. - * If you don't need to see every request, you can leave the base - * implementations of those two functions and instead override - * {@link #startNetwork} and {@link #stopNetwork}. - * - * If you want to see every score fluctuation on every request, set - * your score filter to a very high number and watch {@link #needNetworkFor}. - * - * @return {@code true} to accept the request. - */ - public boolean acceptRequest(@NonNull final NetworkRequest request) { - return true; - } - - /** - * Can be called by a factory to release a request as unfulfillable: the request will be - * removed, and the caller will get a - * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function - * returns. - * - * Note: this should only be called by factory which KNOWS that it is the ONLY factory which - * is able to fulfill this request! - */ - protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { - mImpl.releaseRequestAsUnfulfillableByAnyFactory(r); - } - - // override to do simple mode (request independent) - protected void startNetwork() { } - protected void stopNetwork() { } - - // override to do fancier stuff - protected void needNetworkFor(@NonNull final NetworkRequest networkRequest) { - if (++mRefCount == 1) startNetwork(); - } - - protected void releaseNetworkFor(@NonNull final NetworkRequest networkRequest) { - if (--mRefCount == 0) stopNetwork(); - } - - /** - * @deprecated this method was never part of the API (system or public) and is only added - * for migration of existing clients. - */ - @Deprecated - public void setScoreFilter(final int score) { - mImpl.setScoreFilter(score); - } - - /** - * Set a score filter for this factory. - * - * This should include the transports the factory knows its networks will have, and - * an optimistic view of the attributes it may have. This does not commit the factory - * to being able to bring up such a network ; it only lets it avoid hearing about - * requests that it has no chance of fulfilling. - * - * @param score the filter - */ - public void setScoreFilter(@NonNull final NetworkScore score) { - mImpl.setScoreFilter(score); - } - - public void setCapabilityFilter(NetworkCapabilities netCap) { - mImpl.setCapabilityFilter(netCap); - } - - @VisibleForTesting - protected int getRequestCount() { - return mImpl.getRequestCount(); - } - - public int getSerialNumber() { - return mImpl.getSerialNumber(); - } - - public NetworkProvider getProvider() { - return mImpl.getProvider(); - } - - protected void log(String s) { - Log.d(LOG_TAG, s); - } - - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - mImpl.dump(fd, writer, args); - } - - @Override - public String toString() { - return "{" + LOG_TAG + " " + mImpl.toString() + "}"; - } -} diff --git a/common/device/android/net/NetworkFactoryImpl.java b/common/device/android/net/NetworkFactoryImpl.java deleted file mode 100644 index 9c1190c2..00000000 --- a/common/device/android/net/NetworkFactoryImpl.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.Context; -import android.net.NetworkProvider.NetworkOfferCallback; -import android.os.Looper; -import android.os.Message; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.concurrent.Executor; - -/** - * A NetworkFactory is an entity that creates NetworkAgent objects. - * The bearers register with ConnectivityService using {@link #register} and - * their factory will start receiving scored NetworkRequests. NetworkRequests - * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by - * overridden function. All of these can be dynamic - changing NetworkCapabilities - * or score forces re-evaluation of all current requests. - * - * If any requests pass the filter some overrideable functions will be called. - * If the bearer only cares about very simple start/stopNetwork callbacks, those - * functions can be overridden. If the bearer needs more interaction, it can - * override addNetworkRequest and removeNetworkRequest which will give it each - * request that passes their current filters. - * @hide - **/ -// TODO(b/187083878): factor out common code between this and NetworkFactoryLegacyImpl -class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { - private static final boolean DBG = NetworkFactory.DBG; - private static final boolean VDBG = NetworkFactory.VDBG; - - // A score that will win against everything, so that score filtering will let all requests - // through - // TODO : remove this and replace with an API to listen to all requests. - @NonNull - private static final NetworkScore INVINCIBLE_SCORE = - new NetworkScore.Builder().setLegacyInt(1000).build(); - - // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to - // run the tasks asynchronously on the Handler thread. - - /** - * Pass a network request to the bearer. If the bearer believes it can - * satisfy the request it should connect to the network and create a - * NetworkAgent. Once the NetworkAgent is fully functional it will - * register itself with ConnectivityService using registerNetworkAgent. - * If the bearer cannot immediately satisfy the request (no network, - * user disabled the radio, lower-scored network) it should remember - * any NetworkRequests it may be able to satisfy in the future. It may - * disregard any that it will never be able to service, for example - * those requiring a different bearer. - * msg.obj = NetworkRequest - */ - // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests - // and remove them and the associated code. - private static final int CMD_REQUEST_NETWORK = NetworkFactory.CMD_REQUEST_NETWORK; - - /** - * Cancel a network request - * msg.obj = NetworkRequest - */ - private static final int CMD_CANCEL_REQUEST = NetworkFactory.CMD_CANCEL_REQUEST; - - /** - * Internally used to set our best-guess score. - * msg.obj = new score - */ - private static final int CMD_SET_SCORE = 3; - - /** - * Internally used to set our current filter for coarse bandwidth changes with - * technology changes. - * msg.obj = new filter - */ - private static final int CMD_SET_FILTER = 4; - - /** - * Internally used to send the network offer associated with this factory. - * No arguments, will read from members - */ - private static final int CMD_OFFER_NETWORK = 5; - - /** - * Internally used to send the request to listen to all requests. - * No arguments, will read from members - */ - private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; - - private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = - new LinkedHashMap<>(); - - @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); - - private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { - @Override - public void onNetworkNeeded(@NonNull final NetworkRequest request) { - handleAddRequest(request); - } - - @Override - public void onNetworkUnneeded(@NonNull final NetworkRequest request) { - handleRemoveRequest(request); - } - }; - @NonNull private final Executor mExecutor = command -> post(command); - - - // Ideally the filter argument would be non-null, but null has historically meant to see - // no requests and telephony passes null. - NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, - @Nullable final NetworkCapabilities filter) { - super(parent, looper, context, - null != filter ? filter : - NetworkCapabilities.Builder.withoutDefaultCapabilities().build()); - } - - /* Registers this NetworkFactory with the system. May only be called once per factory. */ - @Override public void register(final String logTag) { - register(logTag, false); - } - - /** - * Registers this NetworkFactory with the system ignoring the score filter. This will let - * the factory always see all network requests matching its capabilities filter. - * May only be called once per factory. - */ - @Override public void registerIgnoringScore(final String logTag) { - register(logTag, true); - } - - private void register(final String logTag, final boolean listenToAllRequests) { - if (mProvider != null) { - throw new IllegalStateException("A NetworkFactory must only be registered once"); - } - if (DBG) mParent.log("Registering NetworkFactory"); - - mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) { - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, - int servingProviderId) { - handleAddRequest(request); - } - - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - handleRemoveRequest(request); - } - }; - - ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); - - // The mScore and mCapabilityFilter members can only be accessed on the handler thread. - // TODO : offer a separate API to listen to all requests instead - if (listenToAllRequests) { - sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); - } else { - sendMessage(obtainMessage(CMD_OFFER_NETWORK)); - } - } - - private void handleOfferNetwork(@NonNull final NetworkScore score) { - mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj); - break; - } - case CMD_CANCEL_REQUEST: { - handleRemoveRequest((NetworkRequest) msg.obj); - break; - } - case CMD_SET_SCORE: { - handleSetScore((NetworkScore) msg.obj); - break; - } - case CMD_SET_FILTER: { - handleSetFilter((NetworkCapabilities) msg.obj); - break; - } - case CMD_OFFER_NETWORK: { - handleOfferNetwork(mScore); - break; - } - case CMD_LISTEN_TO_ALL_REQUESTS: { - handleOfferNetwork(INVINCIBLE_SCORE); - break; - } - } - } - - private static class NetworkRequestInfo { - @NonNull public final NetworkRequest request; - public boolean requested; // do we have a request outstanding, limited by score - - NetworkRequestInfo(@NonNull final NetworkRequest request) { - this.request = request; - this.requested = false; - } - - @Override - public String toString() { - return "{" + request + ", requested=" + requested + "}"; - } - } - - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - */ - private void handleAddRequest(@NonNull final NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n == null) { - if (DBG) mParent.log("got request " + request); - n = new NetworkRequestInfo(request); - mNetworkRequests.put(n.request, n); - } else { - if (VDBG) mParent.log("handle existing request " + request); - } - if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - - if (mParent.acceptRequest(request)) { - n.requested = true; - mParent.needNetworkFor(request); - } - } - - private void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n != null) { - mNetworkRequests.remove(request); - if (n.requested) mParent.releaseNetworkFor(n.request); - } - } - - private void handleSetScore(@NonNull final NetworkScore score) { - if (mScore.equals(score)) return; - mScore = score; - mParent.reevaluateAllRequests(); - } - - private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { - if (netCap.equals(mCapabilityFilter)) return; - mCapabilityFilter = netCap; - mParent.reevaluateAllRequests(); - } - - @Override public final void reevaluateAllRequests() { - if (mProvider == null) return; - mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); - } - - /** - * @deprecated this method was never part of the API (system or public) and is only added - * for migration of existing clients. - */ - @Deprecated - public void setScoreFilter(final int score) { - setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); - } - - /** - * Set a score filter for this factory. - * - * This should include the transports the factory knows its networks will have, and - * an optimistic view of the attributes it may have. This does not commit the factory - * to being able to bring up such a network ; it only lets it avoid hearing about - * requests that it has no chance of fulfilling. - * - * @param score the filter - */ - @Override public void setScoreFilter(@NonNull final NetworkScore score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score)); - } - - @Override public void setCapabilityFilter(NetworkCapabilities netCap) { - sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); - } - - @Override public int getRequestCount() { - return mNetworkRequests.size(); - } - - @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println(toString()); - for (NetworkRequestInfo n : mNetworkRequests.values()) { - writer.println(" " + n); - } - } - - @Override public String toString() { - return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") - + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter - + ", requests=" + mNetworkRequests.size(); - } -} diff --git a/common/device/android/net/NetworkFactoryLegacyImpl.java b/common/device/android/net/NetworkFactoryLegacyImpl.java deleted file mode 100644 index 6cba6258..00000000 --- a/common/device/android/net/NetworkFactoryLegacyImpl.java +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.content.Context; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * A NetworkFactory is an entity that creates NetworkAgent objects. - * The bearers register with ConnectivityService using {@link #register} and - * their factory will start receiving scored NetworkRequests. NetworkRequests - * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by - * overridden function. All of these can be dynamic - changing NetworkCapabilities - * or score forces re-evaluation of all current requests. - * - * If any requests pass the filter some overrideable functions will be called. - * If the bearer only cares about very simple start/stopNetwork callbacks, those - * functions can be overridden. If the bearer needs more interaction, it can - * override addNetworkRequest and removeNetworkRequest which will give it each - * request that passes their current filters. - * @hide - **/ -// TODO(b/187083878): factor out common code between this and NetworkFactoryImpl -class NetworkFactoryLegacyImpl extends Handler - implements NetworkFactoryShim { - private static final boolean DBG = NetworkFactory.DBG; - private static final boolean VDBG = NetworkFactory.VDBG; - - // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to - // run the tasks asynchronously on the Handler thread. - - /** - * Pass a network request to the bearer. If the bearer believes it can - * satisfy the request it should connect to the network and create a - * NetworkAgent. Once the NetworkAgent is fully functional it will - * register itself with ConnectivityService using registerNetworkAgent. - * If the bearer cannot immediately satisfy the request (no network, - * user disabled the radio, lower-scored network) it should remember - * any NetworkRequests it may be able to satisfy in the future. It may - * disregard any that it will never be able to service, for example - * those requiring a different bearer. - * msg.obj = NetworkRequest - * msg.arg1 = score - the score of the network currently satisfying this - * request. If this bearer knows in advance it cannot - * exceed this score it should not try to connect, holding the request - * for the future. - * Note that subsequent events may give a different (lower - * or higher) score for this request, transmitted to each - * NetworkFactory through additional CMD_REQUEST_NETWORK msgs - * with the same NetworkRequest but an updated score. - * Also, network conditions may change for this bearer - * allowing for a better score in the future. - * msg.arg2 = the ID of the NetworkProvider currently responsible for the - * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. - */ - public static final int CMD_REQUEST_NETWORK = 1; - - /** - * Cancel a network request - * msg.obj = NetworkRequest - */ - public static final int CMD_CANCEL_REQUEST = 2; - - /** - * Internally used to set our best-guess score. - * msg.arg1 = new score - */ - private static final int CMD_SET_SCORE = 3; - - /** - * Internally used to set our current filter for coarse bandwidth changes with - * technology changes. - * msg.obj = new filter - */ - private static final int CMD_SET_FILTER = 4; - - final Context mContext; - final NetworkFactory mParent; - - private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = - new LinkedHashMap<>(); - - private int mScore; - NetworkCapabilities mCapabilityFilter; - - NetworkProvider mProvider = null; - - NetworkFactoryLegacyImpl(NetworkFactory parent, Looper looper, Context context, - NetworkCapabilities filter) { - super(looper); - mParent = parent; - mContext = context; - mCapabilityFilter = filter; - } - - /* Registers this NetworkFactory with the system. May only be called once per factory. */ - @Override public void register(final String logTag) { - if (mProvider != null) { - throw new IllegalStateException("A NetworkFactory must only be registered once"); - } - if (DBG) mParent.log("Registering NetworkFactory"); - - mProvider = new NetworkProvider(mContext, NetworkFactoryLegacyImpl.this.getLooper(), - logTag) { - @Override - public void onNetworkRequested(@NonNull NetworkRequest request, int score, - int servingProviderId) { - handleAddRequest(request, score, servingProviderId); - } - - @Override - public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { - handleRemoveRequest(request); - } - }; - - ((ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); - } - - /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ - @Override public void terminate() { - if (mProvider == null) { - throw new IllegalStateException("This NetworkFactory was never registered"); - } - if (DBG) mParent.log("Unregistering NetworkFactory"); - - ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) - .unregisterNetworkProvider(mProvider); - - // Remove all pending messages, since this object cannot be reused. Any message currently - // being processed will continue to run. - removeCallbacksAndMessages(null); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case CMD_REQUEST_NETWORK: { - handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); - break; - } - case CMD_CANCEL_REQUEST: { - handleRemoveRequest((NetworkRequest) msg.obj); - break; - } - case CMD_SET_SCORE: { - handleSetScore(msg.arg1); - break; - } - case CMD_SET_FILTER: { - handleSetFilter((NetworkCapabilities) msg.obj); - break; - } - } - } - - private static class NetworkRequestInfo { - public final NetworkRequest request; - public int score; - public boolean requested; // do we have a request outstanding, limited by score - public int providerId; - - NetworkRequestInfo(NetworkRequest request, int score, int providerId) { - this.request = request; - this.score = score; - this.requested = false; - this.providerId = providerId; - } - - @Override - public String toString() { - return "{" + request + ", score=" + score + ", requested=" + requested + "}"; - } - } - - /** - * Add a NetworkRequest that the bearer may want to attempt to satisfy. - * @see #CMD_REQUEST_NETWORK - * - * @param request the request to handle. - * @param score the score of the NetworkAgent currently satisfying this request. - * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent - * currently satisfying this request. - */ - @VisibleForTesting - protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n == null) { - if (DBG) { - mParent.log("got request " + request + " with score " + score - + " and providerId " + servingProviderId); - } - n = new NetworkRequestInfo(request, score, servingProviderId); - mNetworkRequests.put(n.request, n); - } else { - if (VDBG) { - mParent.log("new score " + score + " for existing request " + request - + " and providerId " + servingProviderId); - } - n.score = score; - n.providerId = servingProviderId; - } - if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); - - evalRequest(n); - } - - private void handleRemoveRequest(NetworkRequest request) { - NetworkRequestInfo n = mNetworkRequests.get(request); - if (n != null) { - mNetworkRequests.remove(request); - if (n.requested) mParent.releaseNetworkFor(n.request); - } - } - - private void handleSetScore(int score) { - mScore = score; - evalRequests(); - } - - private void handleSetFilter(NetworkCapabilities netCap) { - mCapabilityFilter = netCap; - evalRequests(); - } - - /** - * Overridable function to provide complex filtering. - * Called for every request every time a new NetworkRequest is seen - * and whenever the filterScore or filterNetworkCapabilities change. - * - * acceptRequest can be overridden to provide complex filter behavior - * for the incoming requests - * - * For output, this class will call {@link NetworkFactory#needNetworkFor} and - * {@link NetworkFactory#releaseNetworkFor} for every request that passes the filters. - * If you don't need to see every request, you can leave the base - * implementations of those two functions and instead override - * {@link NetworkFactory#startNetwork} and {@link NetworkFactory#stopNetwork}. - * - * If you want to see every score fluctuation on every request, set - * your score filter to a very high number and watch {@link NetworkFactory#needNetworkFor}. - * - * @return {@code true} to accept the request. - */ - public boolean acceptRequest(NetworkRequest request) { - return mParent.acceptRequest(request); - } - - private void evalRequest(NetworkRequestInfo n) { - if (VDBG) { - mParent.log("evalRequest"); - mParent.log(" n.requests = " + n.requested); - mParent.log(" n.score = " + n.score); - mParent.log(" mScore = " + mScore); - mParent.log(" request.providerId = " + n.providerId); - mParent.log(" mProvider.id = " + mProvider.getProviderId()); - } - if (shouldNeedNetworkFor(n)) { - if (VDBG) mParent.log(" needNetworkFor"); - mParent.needNetworkFor(n.request); - n.requested = true; - } else if (shouldReleaseNetworkFor(n)) { - if (VDBG) mParent.log(" releaseNetworkFor"); - mParent.releaseNetworkFor(n.request); - n.requested = false; - } else { - if (VDBG) mParent.log(" done"); - } - } - - private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { - // If this request is already tracked, it doesn't qualify for need - return !n.requested - // If the score of this request is higher or equal to that of this factory and some - // other factory is responsible for it, then this factory should not track the request - // because it has no hope of satisfying it. - && (n.score < mScore || n.providerId == mProvider.getProviderId()) - // If this factory can't satisfy the capability needs of this request, then it - // should not be tracked. - && n.request.canBeSatisfiedBy(mCapabilityFilter) - // Finally if the concrete implementation of the factory rejects the request, then - // don't track it. - && acceptRequest(n.request); - } - - private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { - // Don't release a request that's not tracked. - return n.requested - // The request should be released if it can't be satisfied by this factory. That - // means either of the following conditions are met : - // - Its score is too high to be satisfied by this factory and it's not already - // assigned to the factory - // - This factory can't satisfy the capability needs of the request - // - The concrete implementation of the factory rejects the request - && ((n.score > mScore && n.providerId != mProvider.getProviderId()) - || !n.request.canBeSatisfiedBy(mCapabilityFilter) - || !acceptRequest(n.request)); - } - - private void evalRequests() { - for (NetworkRequestInfo n : mNetworkRequests.values()) { - evalRequest(n); - } - } - - /** - * Post a command, on this NetworkFactory Handler, to re-evaluate all - * outstanding requests. Can be called from a factory implementation. - */ - @Override public void reevaluateAllRequests() { - post(this::evalRequests); - } - - /** - * Can be called by a factory to release a request as unfulfillable: the request will be - * removed, and the caller will get a - * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function - * returns. - * - * Note: this should only be called by factory which KNOWS that it is the ONLY factory which - * is able to fulfill this request! - */ - @Override public void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { - post(() -> { - if (DBG) mParent.log("releaseRequestAsUnfulfillableByAnyFactory: " + r); - final NetworkProvider provider = mProvider; - if (provider == null) { - mParent.log("Ignoring attempt to release unregistered request as unfulfillable"); - return; - } - provider.declareNetworkRequestUnfulfillable(r); - }); - } - - @Override public void setScoreFilter(int score) { - sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); - } - - @Override public void setScoreFilter(@NonNull final NetworkScore score) { - setScoreFilter(score.getLegacyInt()); - } - - @Override public void setCapabilityFilter(NetworkCapabilities netCap) { - sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); - } - - @Override public int getRequestCount() { - return mNetworkRequests.size(); - } - - /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ - @Override public int getSerialNumber() { - return mProvider.getProviderId(); - } - - @Override public NetworkProvider getProvider() { - return mProvider; - } - - @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - writer.println(toString()); - for (NetworkRequestInfo n : mNetworkRequests.values()) { - writer.println(" " + n); - } - } - - @Override public String toString() { - return "providerId=" + (mProvider != null ? mProvider.getProviderId() : "null") - + ", ScoreFilter=" + mScore + ", Filter=" + mCapabilityFilter - + ", requests=" + mNetworkRequests.size(); - } -} diff --git a/common/device/android/net/NetworkFactoryShim.java b/common/device/android/net/NetworkFactoryShim.java deleted file mode 100644 index dfbb5ec1..00000000 --- a/common/device/android/net/NetworkFactoryShim.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2021 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; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Looper; -import android.os.Message; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Extract an interface for multiple implementation of {@link NetworkFactory}, depending on the SDK - * version. - * - * Known implementations: - * - {@link NetworkFactoryImpl}: For Android S+ - * - {@link NetworkFactoryLegacyImpl}: For Android R- - * - * @hide - */ -interface NetworkFactoryShim { - void register(String logTag); - - default void registerIgnoringScore(String logTag) { - throw new UnsupportedOperationException(); - } - - void terminate(); - - void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r); - - void reevaluateAllRequests(); - - void setScoreFilter(int score); - - void setScoreFilter(@NonNull NetworkScore score); - - void setCapabilityFilter(NetworkCapabilities netCap); - - int getRequestCount(); - - int getSerialNumber(); - - NetworkProvider getProvider(); - - void dump(FileDescriptor fd, PrintWriter writer, String[] args); - - // All impls inherit Handler - @VisibleForTesting - Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj); - - Looper getLooper(); -} diff --git a/common/device/com/android/net/module/util/BpfBitmap.java b/common/device/com/android/net/module/util/BpfBitmap.java deleted file mode 100644 index d2a5b654..00000000 --- a/common/device/com/android/net/module/util/BpfBitmap.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import android.system.ErrnoException; - -import androidx.annotation.NonNull; - - /** - * - * Generic bitmap class for use with BPF programs. Corresponds to a BpfMap - * array type with key->int and value->uint64_t defined in the bpf program. - * - */ -public class BpfBitmap { - private BpfMap<Struct.S32, Struct.S64> mBpfMap; - - /** - * Create a BpfBitmap map wrapper with "path" of filesystem. - * - * @param path The path of the BPF map. - */ - public BpfBitmap(@NonNull String path) throws ErrnoException { - mBpfMap = new BpfMap<Struct.S32, Struct.S64>(path, BpfMap.BPF_F_RDWR, - Struct.S32.class, Struct.S64.class); - } - - /** - * Retrieves the value from BpfMap for the given key. - * - * @param key The key in the map corresponding to the value to return. - */ - private long getBpfMapValue(Struct.S32 key) throws ErrnoException { - Struct.S64 curVal = mBpfMap.getValue(key); - if (curVal != null) { - return curVal.val; - } else { - return 0; - } - } - - /** - * Retrieves the bit for the given index in the bitmap. - * - * @param index Position in bitmap. - */ - public boolean get(int index) throws ErrnoException { - if (index < 0) return false; - - Struct.S32 key = new Struct.S32(index >> 6); - return ((getBpfMapValue(key) >>> (index & 63)) & 1L) != 0; - } - - /** - * Set the specified index in the bitmap. - * - * @param index Position to set in bitmap. - */ - public void set(int index) throws ErrnoException { - set(index, true); - } - - /** - * Unset the specified index in the bitmap. - * - * @param index Position to unset in bitmap. - */ - public void unset(int index) throws ErrnoException { - set(index, false); - } - - /** - * Change the specified index in the bitmap to set value. - * - * @param index Position to unset in bitmap. - * @param set Boolean indicating to set or unset index. - */ - public void set(int index, boolean set) throws ErrnoException { - if (index < 0) throw new IllegalArgumentException("Index out of bounds."); - - Struct.S32 key = new Struct.S32(index >> 6); - long mask = (1L << (index & 63)); - long val = getBpfMapValue(key); - if (set) val |= mask; else val &= ~mask; - mBpfMap.updateEntry(key, new Struct.S64(val)); - } - - /** - * Clears the map. The map may already be empty. - * - * @throws ErrnoException if updating entry to 0 fails. - */ - public void clear() throws ErrnoException { - mBpfMap.forEach((key, value) -> { - mBpfMap.updateEntry(key, new Struct.S64(0)); - }); - } - - /** - * Checks if all bitmap values are 0. - */ - public boolean isEmpty() throws ErrnoException { - Struct.S32 key = mBpfMap.getFirstKey(); - while (key != null) { - if (getBpfMapValue(key) != 0) { - return false; - } - key = mBpfMap.getNextKey(key); - } - return true; - } -} diff --git a/common/device/com/android/net/module/util/BpfDump.java b/common/device/com/android/net/module/util/BpfDump.java deleted file mode 100644 index 7549e712..00000000 --- a/common/device/com/android/net/module/util/BpfDump.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import static android.system.OsConstants.R_OK; - -import android.system.ErrnoException; -import android.system.Os; -import android.util.Base64; -import android.util.Pair; - -import androidx.annotation.NonNull; - -import java.io.PrintWriter; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.function.BiFunction; - -/** - * The classes and the methods for BPF dump utilization. - */ -public class BpfDump { - // Using "," as a separator between base64 encoded key and value is safe because base64 - // characters are [0-9a-zA-Z/=+]. - private static final String BASE64_DELIMITER = ","; - - /** - * Encode BPF key and value into a base64 format string which uses the delimiter ',': - * <base64 encoded key>,<base64 encoded value> - */ - public static <K extends Struct, V extends Struct> String toBase64EncodedString( - @NonNull final K key, @NonNull final V value) { - final byte[] keyBytes = key.writeToBytes(); - final String keyBase64Str = Base64.encodeToString(keyBytes, Base64.DEFAULT) - .replace("\n", ""); - final byte[] valueBytes = value.writeToBytes(); - final String valueBase64Str = Base64.encodeToString(valueBytes, Base64.DEFAULT) - .replace("\n", ""); - - return keyBase64Str + BASE64_DELIMITER + valueBase64Str; - } - - /** - * Decode Struct from a base64 format string - */ - private static <T extends Struct> T parseStruct( - Class<T> structClass, @NonNull String base64Str) { - final byte[] bytes = Base64.decode(base64Str, Base64.DEFAULT); - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - return Struct.parse(structClass, byteBuffer); - } - - /** - * Decode BPF key and value from a base64 format string which uses the delimiter ',': - * <base64 encoded key>,<base64 encoded value> - */ - public static <K extends Struct, V extends Struct> Pair<K, V> fromBase64EncodedString( - Class<K> keyClass, Class<V> valueClass, @NonNull String base64Str) { - String[] keyValueStrs = base64Str.split(BASE64_DELIMITER); - if (keyValueStrs.length != 2 /* key + value */) { - throw new IllegalArgumentException("Invalid base64Str (" + base64Str + "), base64Str" - + " must contain exactly one delimiter '" + BASE64_DELIMITER + "'"); - } - final K k = parseStruct(keyClass, keyValueStrs[0]); - final V v = parseStruct(valueClass, keyValueStrs[1]); - return new Pair<>(k, v); - } - - /** - * Dump the BpfMap name and entries - */ - public static <K extends Struct, V extends Struct> void dumpMap(IBpfMap<K, V> map, - PrintWriter pw, String mapName, BiFunction<K, V, String> entryToString) { - dumpMap(map, pw, mapName, "" /* header */, entryToString); - } - - /** - * Dump the BpfMap name, header, and entries - */ - public static <K extends Struct, V extends Struct> void dumpMap(IBpfMap<K, V> map, - PrintWriter pw, String mapName, String header, BiFunction<K, V, String> entryToString) { - pw.println(mapName + ":"); - if (!header.isEmpty()) { - pw.println(" " + header); - } - try { - map.forEach((key, value) -> { - // Value could be null if there is a concurrent entry deletion. - // http://b/220084230. - if (value != null) { - pw.println(" " + entryToString.apply(key, value)); - } else { - pw.println("Entry is deleted while dumping, iterating from first entry"); - } - }); - } catch (ErrnoException e) { - pw.println("Map dump end with error: " + Os.strerror(e.errno)); - } - } - - /** - * Dump the BpfMap status - */ - public static <K extends Struct, V extends Struct> void dumpMapStatus(IBpfMap<K, V> map, - PrintWriter pw, String mapName, String path) { - if (map != null) { - pw.println(mapName + ": OK"); - return; - } - try { - Os.access(path, R_OK); - pw.println(mapName + ": NULL(map is pinned to " + path + ")"); - } catch (ErrnoException e) { - pw.println(mapName + ": NULL(map is not pinned to " + path + ": " - + Os.strerror(e.errno) + ")"); - } - } - - // TODO: add a helper to dump bpf map content with the map name, the header line - // (ex: "BPF ingress map: iif nat64Prefix v6Addr -> v4Addr oif"), a lambda that - // knows how to dump each line, and the PrintWriter. -} diff --git a/common/device/com/android/net/module/util/BpfMap.java b/common/device/com/android/net/module/util/BpfMap.java deleted file mode 100644 index d45caceb..00000000 --- a/common/device/com/android/net/module/util/BpfMap.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util; - -import static android.system.OsConstants.EEXIST; -import static android.system.OsConstants.ENOENT; - -import android.os.ParcelFileDescriptor; -import android.system.ErrnoException; -import android.util.Pair; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * BpfMap is a key -> value mapping structure that is designed to maintained the bpf map entries. - * This is a wrapper class of in-kernel data structure. The in-kernel data can be read/written by - * passing syscalls with map file descriptor. - * - * @param <K> the key of the map. - * @param <V> the value of the map. - */ -public class BpfMap<K extends Struct, V extends Struct> implements IBpfMap<K, V> { - static { - System.loadLibrary(JniUtil.getJniLibraryName(BpfMap.class.getPackage())); - } - - // Following definitions from kernel include/uapi/linux/bpf.h - public static final int BPF_F_RDWR = 0; - public static final int BPF_F_RDONLY = 1 << 3; - public static final int BPF_F_WRONLY = 1 << 4; - - public static final int BPF_MAP_TYPE_HASH = 1; - - private static final int BPF_F_NO_PREALLOC = 1; - - private static final int BPF_ANY = 0; - private static final int BPF_NOEXIST = 1; - private static final int BPF_EXIST = 2; - - private final ParcelFileDescriptor mMapFd; - private final Class<K> mKeyClass; - private final Class<V> mValueClass; - private final int mKeySize; - private final int mValueSize; - - private static ConcurrentHashMap<Pair<String, Integer>, ParcelFileDescriptor> sFdCache = - new ConcurrentHashMap<>(); - - private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode, - int keySize, int valueSize) - throws ErrnoException, NullPointerException { - // Supports up to 1023 byte key and 65535 byte values - // Creating a BpfMap with larger keys/values seems like a bad idea any way... - keySize &= 1023; // 10-bits - valueSize &= 65535; // 16-bits - var key = Pair.create(path, (mode << 26) ^ (keySize << 16) ^ valueSize); - // unlocked fetch is safe: map is concurrent read capable, and only inserted into - ParcelFileDescriptor fd = sFdCache.get(key); - if (fd != null) return fd; - // ok, no cached fd present, need to grab a lock - synchronized (BpfMap.class) { - // need to redo the check - fd = sFdCache.get(key); - if (fd != null) return fd; - // okay, we really haven't opened this before... - fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode, keySize, valueSize)); - sFdCache.put(key, fd); - return fd; - } - } - - /** - * Create a BpfMap map wrapper with "path" of filesystem. - * - * @param flag the access mode, one of BPF_F_RDWR, BPF_F_RDONLY, or BPF_F_WRONLY. - * @throws ErrnoException if the BPF map associated with {@code path} cannot be retrieved. - * @throws NullPointerException if {@code path} is null. - */ - public BpfMap(@NonNull final String path, final int flag, final Class<K> key, - final Class<V> value) throws ErrnoException, NullPointerException { - mKeyClass = key; - mValueClass = value; - mKeySize = Struct.getSize(key); - mValueSize = Struct.getSize(value); - mMapFd = cachedBpfFdGet(path, flag, mKeySize, mValueSize); - } - - /** - * Update an existing or create a new key -> value entry in an eBbpf map. - * (use insertOrReplaceEntry() if you need to know whether insert or replace happened) - */ - @Override - public void updateEntry(K key, V value) throws ErrnoException { - nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), BPF_ANY); - } - - /** - * If the key does not exist in the map, insert key -> value entry into eBpf map. - * Otherwise IllegalStateException will be thrown. - */ - @Override - public void insertEntry(K key, V value) - throws ErrnoException, IllegalStateException { - try { - nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), - BPF_NOEXIST); - } catch (ErrnoException e) { - if (e.errno == EEXIST) throw new IllegalStateException(key + " already exists"); - - throw e; - } - } - - /** - * If the key already exists in the map, replace its value. Otherwise NoSuchElementException - * will be thrown. - */ - @Override - public void replaceEntry(K key, V value) - throws ErrnoException, NoSuchElementException { - try { - nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), - BPF_EXIST); - } catch (ErrnoException e) { - if (e.errno == ENOENT) throw new NoSuchElementException(key + " not found"); - - throw e; - } - } - - /** - * Update an existing or create a new key -> value entry in an eBbpf map. - * Returns true if inserted, false if replaced. - * (use updateEntry() if you don't care whether insert or replace happened) - * Note: see inline comment below if running concurrently with delete operations. - */ - @Override - public boolean insertOrReplaceEntry(K key, V value) - throws ErrnoException { - try { - nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), - BPF_NOEXIST); - return true; /* insert succeeded */ - } catch (ErrnoException e) { - if (e.errno != EEXIST) throw e; - } - try { - nativeWriteToMapEntry(mMapFd.getFd(), key.writeToBytes(), value.writeToBytes(), - BPF_EXIST); - return false; /* replace succeeded */ - } catch (ErrnoException e) { - if (e.errno != ENOENT) throw e; - } - /* If we reach here somebody deleted after our insert attempt and before our replace: - * this implies a race happened. The kernel bpf delete interface only takes a key, - * and not the value, so we can safely pretend the replace actually succeeded and - * was immediately followed by the other thread's delete, since the delete cannot - * observe the potential change to the value. - */ - return false; /* pretend replace succeeded */ - } - - /** Remove existing key from eBpf map. Return false if map was not modified. */ - @Override - public boolean deleteEntry(K key) throws ErrnoException { - return nativeDeleteMapEntry(mMapFd.getFd(), key.writeToBytes()); - } - - /** Returns {@code true} if this map contains no elements. */ - @Override - public boolean isEmpty() throws ErrnoException { - return getFirstKey() == null; - } - - private K getNextKeyInternal(@Nullable K key) throws ErrnoException { - byte[] rawKey = new byte[mKeySize]; - - if (!nativeGetNextMapKey(mMapFd.getFd(), - key == null ? null : key.writeToBytes(), - rawKey)) return null; - - final ByteBuffer buffer = ByteBuffer.wrap(rawKey); - buffer.order(ByteOrder.nativeOrder()); - return Struct.parse(mKeyClass, buffer); - } - - /** - * Get the next key of the passed-in key. If the passed-in key is not found, return the first - * key. If the passed-in key is the last one, return null. - * - * TODO: consider allowing null passed-in key. - */ - @Override - public K getNextKey(@NonNull K key) throws ErrnoException { - Objects.requireNonNull(key); - return getNextKeyInternal(key); - } - - /** Get the first key of eBpf map. */ - @Override - public K getFirstKey() throws ErrnoException { - return getNextKeyInternal(null); - } - - /** Check whether a key exists in the map. */ - @Override - public boolean containsKey(@NonNull K key) throws ErrnoException { - Objects.requireNonNull(key); - - byte[] rawValue = new byte[mValueSize]; - return nativeFindMapEntry(mMapFd.getFd(), key.writeToBytes(), rawValue); - } - - /** Retrieve a value from the map. Return null if there is no such key. */ - @Override - public V getValue(@NonNull K key) throws ErrnoException { - Objects.requireNonNull(key); - - byte[] rawValue = new byte[mValueSize]; - if (!nativeFindMapEntry(mMapFd.getFd(), key.writeToBytes(), rawValue)) return null; - - final ByteBuffer buffer = ByteBuffer.wrap(rawValue); - buffer.order(ByteOrder.nativeOrder()); - return Struct.parse(mValueClass, buffer); - } - - /** - * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. - * The given BiConsumer may to delete the passed-in entry, but is not allowed to perform any - * other structural modifications to the map, such as adding entries or deleting other entries. - * Otherwise, iteration will result in undefined behaviour. - */ - @Override - public void forEach(ThrowingBiConsumer<K, V> action) throws ErrnoException { - @Nullable K nextKey = getFirstKey(); - - while (nextKey != null) { - @NonNull final K curKey = nextKey; - @NonNull final V value = getValue(curKey); - - nextKey = getNextKey(curKey); - action.accept(curKey, value); - } - } - - /* Empty implementation to implement AutoCloseable, so we can use BpfMaps - * with try with resources, but due to persistent FD cache, there is no actual - * need to close anything. File descriptors will actually be closed when we - * unlock the BpfMap class and destroy the ParcelFileDescriptor objects. - */ - @Override - public void close() throws IOException { - } - - /** - * Clears the map. The map may already be empty. - * - * @throws ErrnoException if the map is already closed, if an error occurred during iteration, - * or if a non-ENOENT error occurred when deleting a key. - */ - @Override - public void clear() throws ErrnoException { - K key = getFirstKey(); - while (key != null) { - deleteEntry(key); // ignores ENOENT. - key = getFirstKey(); - } - } - - private static native int nativeBpfFdGet(String path, int mode, int keySize, int valueSize) - throws ErrnoException, NullPointerException; - - // Note: the following methods appear to not require the object by virtue of taking the - // fd as an int argument, but the hidden reference to this is actually what prevents - // the object from being garbage collected (and thus potentially maps closed) prior - // to the native code actually running (with a possibly already closed fd). - - private native void nativeWriteToMapEntry(int fd, byte[] key, byte[] value, int flags) - throws ErrnoException; - - private native boolean nativeDeleteMapEntry(int fd, byte[] key) throws ErrnoException; - - // If key is found, the operation returns true and the nextKey would reference to the next - // element. If key is not found, the operation returns true and the nextKey would reference to - // the first element. If key is the last element, false is returned. - private native boolean nativeGetNextMapKey(int fd, byte[] key, byte[] nextKey) - throws ErrnoException; - - private native boolean nativeFindMapEntry(int fd, byte[] key, byte[] value) - throws ErrnoException; -} diff --git a/common/device/com/android/net/module/util/BpfUtils.java b/common/device/com/android/net/module/util/BpfUtils.java deleted file mode 100644 index 94af11b3..00000000 --- a/common/device/com/android/net/module/util/BpfUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import androidx.annotation.NonNull; - -import java.io.IOException; - -/** - * The classes and the methods for BPF utilization. - * - * {@hide} - */ -public class BpfUtils { - static { - System.loadLibrary(JniUtil.getJniLibraryName(BpfUtils.class.getPackage())); - } - - // Defined in include/uapi/linux/bpf.h. Only adding the CGROUPS currently being used for now. - public static final int BPF_CGROUP_INET_INGRESS = 0; - public static final int BPF_CGROUP_INET_EGRESS = 1; - public static final int BPF_CGROUP_INET4_BIND = 8; - public static final int BPF_CGROUP_INET6_BIND = 9; - - - /** - * Attach BPF program to CGROUP - */ - public static void attachProgram(int type, @NonNull String programPath, - @NonNull String cgroupPath, int flags) throws IOException { - native_attachProgramToCgroup(type, programPath, cgroupPath, flags); - } - - /** - * Detach BPF program from CGROUP - */ - public static void detachProgram(int type, @NonNull String cgroupPath) - throws IOException { - native_detachProgramFromCgroup(type, cgroupPath); - } - - /** - * Detach single BPF program from CGROUP - */ - public static void detachSingleProgram(int type, @NonNull String programPath, - @NonNull String cgroupPath) throws IOException { - native_detachSingleProgramFromCgroup(type, programPath, cgroupPath); - } - - private static native boolean native_attachProgramToCgroup(int type, String programPath, - String cgroupPath, int flags) throws IOException; - private static native boolean native_detachProgramFromCgroup(int type, String cgroupPath) - throws IOException; - private static native boolean native_detachSingleProgramFromCgroup(int type, - String programPath, String cgroupPath) throws IOException; -} diff --git a/common/device/com/android/net/module/util/DeviceConfigUtils.java b/common/device/com/android/net/module/util/DeviceConfigUtils.java deleted file mode 100644 index fb130f67..00000000 --- a/common/device/com/android/net/module/util/DeviceConfigUtils.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util; - -import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; -import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; -import static android.provider.DeviceConfig.NAMESPACE_TETHERING; - -import static com.android.net.module.util.FeatureVersions.CONNECTIVITY_MODULE_ID; -import static com.android.net.module.util.FeatureVersions.MODULE_MASK; -import static com.android.net.module.util.FeatureVersions.NETWORK_STACK_MODULE_ID; -import static com.android.net.module.util.FeatureVersions.VERSION_MASK; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Resources; -import android.provider.DeviceConfig; -import android.util.Log; - -import androidx.annotation.BoolRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.util.ArrayList; -import java.util.List; - -/** - * Utilities for modules to query {@link DeviceConfig} and flags. - */ -public final class DeviceConfigUtils { - private DeviceConfigUtils() {} - - private static final String TAG = DeviceConfigUtils.class.getSimpleName(); - /** - * DO NOT MODIFY: this may be used by multiple modules that will not see the updated value - * until they are recompiled, so modifying this constant means that different modules may - * be referencing a different tethering module variant, or having a stale reference. - */ - public static final String TETHERING_MODULE_NAME = "com.android.tethering"; - - @VisibleForTesting - public static final String RESOURCES_APK_INTENT = - "com.android.server.connectivity.intent.action.SERVICE_CONNECTIVITY_RESOURCES_APK"; - private static final String CONNECTIVITY_RES_PKG_DIR = "/apex/" + TETHERING_MODULE_NAME + "/"; - - @VisibleForTesting - public static final long DEFAULT_PACKAGE_VERSION = 1000; - - @VisibleForTesting - public static void resetPackageVersionCacheForTest() { - sPackageVersion = -1; - sModuleVersion = -1; - sNetworkStackModuleVersion = -1; - } - - private static volatile long sPackageVersion = -1; - private static long getPackageVersion(@NonNull final Context context) { - // sPackageVersion may be set by another thread just after this check, but querying the - // package version several times on rare occasions is fine. - if (sPackageVersion >= 0) { - return sPackageVersion; - } - try { - final long version = context.getPackageManager().getPackageInfo( - context.getPackageName(), 0).getLongVersionCode(); - sPackageVersion = version; - return version; - } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, "Failed to get package info: " + e); - return DEFAULT_PACKAGE_VERSION; - } - } - - /** - * Look up the value of a property for a particular namespace from {@link DeviceConfig}. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param defaultValue The value to return if the property does not exist or has no valid value. - * @return the corresponding value, or defaultValue if none exists. - */ - @Nullable - public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name, - @Nullable String defaultValue) { - String value = DeviceConfig.getProperty(namespace, name); - return value != null ? value : defaultValue; - } - - /** - * Look up the value of a property for a particular namespace from {@link DeviceConfig}. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param defaultValue The value to return if the property does not exist or its value is null. - * @return the corresponding value, or defaultValue if none exists. - */ - public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, - int defaultValue) { - String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); - try { - return (value != null) ? Integer.parseInt(value) : defaultValue; - } catch (NumberFormatException e) { - return defaultValue; - } - } - - /** - * Look up the value of a property for a particular namespace from {@link DeviceConfig}. - * - * Flags like timeouts should use this method and set an appropriate min/max range: if invalid - * values like "0" or "1" are pushed to devices, everything would timeout. The min/max range - * protects against this kind of breakage. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param minimumValue The minimum value of a property. - * @param maximumValue The maximum value of a property. - * @param defaultValue The value to return if the property does not exist or its value is null. - * @return the corresponding value, or defaultValue if none exists or the fetched value is - * not in the provided range. - */ - public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name, - int minimumValue, int maximumValue, int defaultValue) { - int value = getDeviceConfigPropertyInt(namespace, name, defaultValue); - if (value < minimumValue || value > maximumValue) return defaultValue; - return value; - } - - /** - * Look up the value of a property for a particular namespace from {@link DeviceConfig}. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param defaultValue The value to return if the property does not exist or its value is null. - * @return the corresponding value, or defaultValue if none exists. - */ - public static boolean getDeviceConfigPropertyBoolean(@NonNull String namespace, - @NonNull String name, boolean defaultValue) { - String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */); - return (value != null) ? Boolean.parseBoolean(value) : defaultValue; - } - - /** - * Check whether or not one specific experimental feature for a particular namespace from - * {@link DeviceConfig} is enabled by comparing module package version - * with current version of property. If this property version is valid, the corresponding - * experimental feature would be enabled, otherwise disabled. - * - * This is useful to ensure that if a module install is rolled back, flags are not left fully - * rolled out on a version where they have not been well tested. - * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @return true if this feature is enabled, or false if disabled. - */ - public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, - @NonNull String name) { - return isFeatureEnabled(context, namespace, name, false /* defaultEnabled */); - } - - /** - * Check whether or not one specific experimental feature for a particular namespace from - * {@link DeviceConfig} is enabled by comparing module package version - * with current version of property. If this property version is valid, the corresponding - * experimental feature would be enabled, otherwise disabled. - * - * This is useful to ensure that if a module install is rolled back, flags are not left fully - * rolled out on a version where they have not been well tested. - * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param defaultEnabled The value to return if the property does not exist or its value is - * null. - * @return true if this feature is enabled, or false if disabled. - */ - public static boolean isFeatureEnabled(@NonNull Context context, @NonNull String namespace, - @NonNull String name, boolean defaultEnabled) { - final long packageVersion = getPackageVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); - } - - /** - * Check whether or not one specific experimental feature for a particular namespace from - * {@link DeviceConfig} is enabled by comparing module package version - * with current version of property. If this property version is valid, the corresponding - * experimental feature would be enabled, otherwise disabled. - * - * This is useful to ensure that if a module install is rolled back, flags are not left fully - * rolled out on a version where they have not been well tested. - * @param context The global context information about an app environment. - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @param moduleName The mainline module name which is released as apex. - * @param defaultEnabled The value to return if the property does not exist or its value is - * null. - * @return true if this feature is enabled, or false if disabled. - */ - public static boolean isTetheringFeatureEnabled(@NonNull Context context, - @NonNull String namespace, @NonNull String name, @NonNull String moduleName, - boolean defaultEnabled) { - // TODO: migrate callers to a non-generic isTetheringFeatureEnabled method. - if (!TETHERING_MODULE_NAME.equals(moduleName)) { - throw new IllegalArgumentException( - "This method is only usable by the tethering module"); - } - final long packageVersion = getTetheringModuleVersion(context); - return isFeatureEnabled(context, packageVersion, namespace, name, defaultEnabled); - } - - private static boolean isFeatureEnabled(@NonNull Context context, long packageVersion, - @NonNull String namespace, String name, boolean defaultEnabled) { - final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, - 0 /* default value */); - return (propertyVersion == 0 && defaultEnabled) - || (propertyVersion != 0 && packageVersion >= (long) propertyVersion); - } - - // Guess the tethering module name based on the package prefix of the connectivity resources - // Take the resource package name, cut it before "connectivity" and append "tethering". - // Then resolve that package version number with packageManager. - // If that fails retry by appending "go.tethering" instead - private static long resolveTetheringModuleVersion(@NonNull Context context) - throws PackageManager.NameNotFoundException { - final String pkgPrefix = resolvePkgPrefix(context); - final PackageManager packageManager = context.getPackageManager(); - try { - return packageManager.getPackageInfo(pkgPrefix + "tethering", - PackageManager.MATCH_APEX).getLongVersionCode(); - } catch (PackageManager.NameNotFoundException e) { - Log.d(TAG, "Device is using go modules"); - // fall through - } - - return packageManager.getPackageInfo(pkgPrefix + "go.tethering", - PackageManager.MATCH_APEX).getLongVersionCode(); - } - - private static String resolvePkgPrefix(Context context) { - final String connResourcesPackage = getConnectivityResourcesPackageName(context); - final int pkgPrefixLen = connResourcesPackage.indexOf("connectivity"); - if (pkgPrefixLen < 0) { - throw new IllegalStateException( - "Invalid connectivity resources package: " + connResourcesPackage); - } - - return connResourcesPackage.substring(0, pkgPrefixLen); - } - - private static volatile long sModuleVersion = -1; - private static long getTetheringModuleVersion(@NonNull Context context) { - if (sModuleVersion >= 0) return sModuleVersion; - - try { - sModuleVersion = resolveTetheringModuleVersion(context); - } catch (PackageManager.NameNotFoundException e) { - // It's expected to fail tethering module version resolution on the devices with - // flattened apex - Log.e(TAG, "Failed to resolve tethering module version: " + e); - return DEFAULT_PACKAGE_VERSION; - } - return sModuleVersion; - } - - private static volatile long sNetworkStackModuleVersion = -1; - - /** - * Get networkstack module version. - */ - @VisibleForTesting - static long getNetworkStackModuleVersion(@NonNull Context context) { - if (sNetworkStackModuleVersion >= 0) return sNetworkStackModuleVersion; - - try { - sNetworkStackModuleVersion = resolveNetworkStackModuleVersion(context); - } catch (PackageManager.NameNotFoundException e) { - Log.wtf(TAG, "Failed to resolve networkstack module version: " + e); - return DEFAULT_PACKAGE_VERSION; - } - return sNetworkStackModuleVersion; - } - - private static long resolveNetworkStackModuleVersion(@NonNull Context context) - throws PackageManager.NameNotFoundException { - // TODO(b/293975546): Strictly speaking this is the prefix for connectivity and not - // network stack. In practice, it's the same. Read the prefix from network stack instead. - final String pkgPrefix = resolvePkgPrefix(context); - final PackageManager packageManager = context.getPackageManager(); - try { - return packageManager.getPackageInfo(pkgPrefix + "networkstack", - PackageManager.MATCH_SYSTEM_ONLY).getLongVersionCode(); - } catch (PackageManager.NameNotFoundException e) { - Log.d(TAG, "Device is using go or non-mainline modules"); - // fall through - } - - return packageManager.getPackageInfo(pkgPrefix + "go.networkstack", - PackageManager.MATCH_ALL).getLongVersionCode(); - } - - /** - * Check whether one specific feature is supported from the feature Id. The feature Id is - * composed by a module package Id and version Id from {@link FeatureVersions}. - * - * This is useful when a feature required minimal module version supported and cannot function - * well with a standalone newer module. - * @param context The global context information about an app environment. - * @param featureId The feature id that contains required module id and minimal module version - * @return true if this feature is supported, or false if not supported. - **/ - public static boolean isFeatureSupported(@NonNull Context context, long featureId) { - final long moduleVersion; - final long moduleId = featureId & MODULE_MASK; - if (moduleId == CONNECTIVITY_MODULE_ID) { - moduleVersion = getTetheringModuleVersion(context); - } else if (moduleId == NETWORK_STACK_MODULE_ID) { - moduleVersion = getNetworkStackModuleVersion(context); - } else { - throw new IllegalArgumentException("Unknown module " + moduleId); - } - // Support by default if no module version is available. - return moduleVersion == DEFAULT_PACKAGE_VERSION - || moduleVersion >= (featureId & VERSION_MASK); - } - - /** - * Check whether one specific experimental feature in specific namespace from - * {@link DeviceConfig} is not disabled. Feature can be disabled by setting a non-zero - * value in the property. If the feature is enabled by default and disabled by flag push - * (kill switch), this method should be used. If the feature is disabled by default and - * enabled by flag push, {@link #isFeatureEnabled} should be used. - * - * @param namespace The namespace containing the property to look up. - * @param name The name of the property to look up. - * @return true if this feature is enabled, or false if disabled. - */ - private static boolean isFeatureNotChickenedOut(String namespace, String name) { - final int propertyVersion = getDeviceConfigPropertyInt(namespace, name, - 0 /* default value */); - return propertyVersion == 0; - } - - /** - * Check whether one specific experimental feature in Tethering module from {@link DeviceConfig} - * is not disabled. - * - * @param name The name of the property in tethering module to look up. - * @return true if this feature is enabled, or false if disabled. - */ - public static boolean isTetheringFeatureNotChickenedOut(String name) { - return isFeatureNotChickenedOut(NAMESPACE_TETHERING, name); - } - - /** - * Check whether one specific experimental feature in NetworkStack module from - * {@link DeviceConfig} is not disabled. - * - * @param name The name of the property in NetworkStack module to look up. - * @return true if this feature is enabled, or false if disabled. - */ - public static boolean isNetworkStackFeatureNotChickenedOut(String name) { - return isFeatureNotChickenedOut(NAMESPACE_CONNECTIVITY, name); - } - - /** - * Gets boolean config from resources. - */ - public static boolean getResBooleanConfig(@NonNull final Context context, - @BoolRes int configResource, final boolean defaultValue) { - final Resources res = context.getResources(); - try { - return res.getBoolean(configResource); - } catch (Resources.NotFoundException e) { - return defaultValue; - } - } - - /** - * Gets int config from resources. - */ - public static int getResIntegerConfig(@NonNull final Context context, - @BoolRes int configResource, final int defaultValue) { - final Resources res = context.getResources(); - try { - return res.getInteger(configResource); - } catch (Resources.NotFoundException e) { - return defaultValue; - } - } - - /** - * Get the package name of the ServiceConnectivityResources package, used to provide resources - * for service-connectivity. - */ - @NonNull - public static String getConnectivityResourcesPackageName(@NonNull Context context) { - final List<ResolveInfo> pkgs = new ArrayList<>(context.getPackageManager() - .queryIntentActivities(new Intent(RESOURCES_APK_INTENT), MATCH_SYSTEM_ONLY)); - pkgs.removeIf(pkg -> !pkg.activityInfo.applicationInfo.sourceDir.startsWith( - CONNECTIVITY_RES_PKG_DIR)); - if (pkgs.size() > 1) { - Log.wtf(TAG, "More than one connectivity resources package found: " + pkgs); - } - if (pkgs.isEmpty()) { - throw new IllegalStateException("No connectivity resource package found"); - } - - return pkgs.get(0).activityInfo.applicationInfo.packageName; - } -} diff --git a/common/device/com/android/net/module/util/DomainUtils.java b/common/device/com/android/net/module/util/DomainUtils.java deleted file mode 100644 index b327fd08..00000000 --- a/common/device/com/android/net/module/util/DomainUtils.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util; - -import android.util.ArrayMap; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.DnsPacketUtils.DnsRecordParser; - -import java.nio.BufferOverflowException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; - -/** - * Utilities for encoding/decoding the domain name or domain search list. - * - * @hide - */ -public final class DomainUtils { - private static final String TAG = "DomainUtils"; - private static final int MAX_OPTION_LEN = 255; - - @NonNull - private static String getSubstring(@NonNull final String string, @NonNull final String[] labels, - int index) { - int beginIndex = 0; - for (int i = 0; i < index; i++) { - beginIndex += labels[i].length() + 1; // include the dot - } - return string.substring(beginIndex); - } - - /** - * Encode the given single domain name to byte array, comply with RFC1035 section-3.1. - * - * @return null if the given domain string is invalid, otherwise, return a byte array - * wrapping the encoded domain, not including any padded octets, caller should - * pad zero octets at the end if needed. - */ - @Nullable - public static byte[] encode(@NonNull final String domain) { - if (!DnsRecordParser.isHostName(domain)) return null; - return encode(new String[]{ domain }, false /* compression */); - } - - /** - * Encode the given multiple domain names to byte array, comply with RFC1035 section-3.1 - * and section 4.1.4 (message compression) if enabled. - * - * @return Null if encode fails due to BufferOverflowException, otherwise, return a byte - * array wrapping the encoded domains, not including any padded octets, caller - * should pad zero octets at the end if needed. The byte array may be empty if - * the given domain strings are invalid. - */ - @Nullable - public static byte[] encode(@NonNull final String[] domains, boolean compression) { - try { - final ByteBuffer buffer = ByteBuffer.allocate(MAX_OPTION_LEN); - final ArrayMap<String, Integer> offsetMap = new ArrayMap<>(); - for (int i = 0; i < domains.length; i++) { - if (!DnsRecordParser.isHostName(domains[i])) { - Log.e(TAG, "Skip invalid domain name " + domains[i]); - continue; - } - final String[] labels = domains[i].split("\\."); - for (int j = 0; j < labels.length; j++) { - if (compression) { - final String suffix = getSubstring(domains[i], labels, j); - if (offsetMap.containsKey(suffix)) { - int offsetOfSuffix = offsetMap.get(suffix); - offsetOfSuffix |= 0xC000; - buffer.putShort((short) offsetOfSuffix); - break; // unnecessary to put the compressed string into map - } else { - offsetMap.put(suffix, buffer.position()); - } - } - // encode the domain name string without compression when: - // - compression feature isn't enabled, - // - suffix does not match any string in the map. - final byte[] labelBytes = labels[j].getBytes(StandardCharsets.UTF_8); - buffer.put((byte) labelBytes.length); - buffer.put(labelBytes); - if (j == labels.length - 1) { - // Pad terminate label at the end of last label. - buffer.put((byte) 0); - } - } - } - buffer.flip(); - final byte[] out = new byte[buffer.limit()]; - buffer.get(out); - return out; - } catch (BufferOverflowException e) { - Log.e(TAG, "Fail to encode domain name and stop encoding", e); - return null; - } - } - - /** - * Decode domain name(s) from the given byteBuffer. Decode follows RFC1035 section 3.1 and - * section 4.1.4(message compression). - * - * @return domain name(s) string array with space separated, or empty string if decode fails. - */ - @NonNull - public static ArrayList<String> decode(@NonNull final ByteBuffer buffer, boolean compression) { - final ArrayList<String> domainList = new ArrayList<>(); - while (buffer.remaining() > 0) { - try { - // TODO: replace the recursion with loop in parseName and don't need to pass in the - // maxLabelCount parameter to prevent recursion from overflowing stack. - final String domain = DnsRecordParser.parseName(buffer, 0 /* depth */, - 15 /* maxLabelCount */, compression); - if (!DnsRecordParser.isHostName(domain)) continue; - domainList.add(domain); - } catch (BufferUnderflowException | DnsPacket.ParseException e) { - Log.e(TAG, "Fail to parse domain name and stop parsing", e); - break; - } - } - return domainList; - } -} diff --git a/common/device/com/android/net/module/util/FdEventsReader.java b/common/device/com/android/net/module/util/FdEventsReader.java deleted file mode 100644 index f88883bf..00000000 --- a/common/device/com/android/net/module/util/FdEventsReader.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2016 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 com.android.net.module.util; - -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR; -import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.net.util.SocketUtils; -import android.os.Handler; -import android.os.Looper; -import android.os.MessageQueue; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.util.Log; - -import com.android.internal.annotations.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; - - -/** - * This class encapsulates the mechanics of registering a file descriptor - * with a thread's Looper and handling read events (and errors). - * - * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override - * onStop() and onStart(). - * - * Subclasses can expect a call life-cycle like the following: - * - * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all - * goes well. Implementations may override onStart() for additional initialization. - * - * [2] yield, waiting for read event or error notification: - * - * [a] readPacket() && handlePacket() - * - * [b] if (no error): - * goto 2 - * else: - * goto 3 - * - * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never - * started). Implementations may override onStop() for additional cleanup. - * - * The packet receive buffer is recycled on every read call, so subclasses - * should make any copies they would like inside their handlePacket() - * implementation. - * - * All public methods MUST only be called from the same thread with which - * the Handler constructor argument is associated. - * - * @param <BufferType> the type of the buffer used to read data. - */ -public abstract class FdEventsReader<BufferType> { - private static final String TAG = FdEventsReader.class.getSimpleName(); - private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR; - private static final int UNREGISTER_THIS_FD = 0; - - @NonNull - private final Handler mHandler; - @NonNull - private final MessageQueue mQueue; - @NonNull - private final BufferType mBuffer; - @Nullable - private FileDescriptor mFd; - private long mPacketsReceived; - - protected static void closeFd(FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - - protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) { - mHandler = h; - mQueue = mHandler.getLooper().getQueue(); - mBuffer = buffer; - } - - @VisibleForTesting - @NonNull - protected MessageQueue getMessageQueue() { - return mQueue; - } - - /** Start this FdEventsReader. */ - public boolean start() { - if (!onCorrectThread()) { - throw new IllegalStateException("start() called from off-thread"); - } - - return createAndRegisterFd(); - } - - /** Stop this FdEventsReader and destroy the file descriptor. */ - public void stop() { - if (!onCorrectThread()) { - throw new IllegalStateException("stop() called from off-thread"); - } - - unregisterAndDestroyFd(); - } - - @NonNull - public Handler getHandler() { - return mHandler; - } - - protected abstract int recvBufSize(@NonNull BufferType buffer); - - /** Returns the size of the receive buffer. */ - public int recvBufSize() { - return recvBufSize(mBuffer); - } - - /** - * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}. - * - * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0. - */ - public final long numPacketsReceived() { - return mPacketsReceived; - } - - /** - * Subclasses MUST create the listening socket here, including setting all desired socket - * options, interface or address/port binding, etc. The socket MUST be created nonblocking. - */ - @Nullable - protected abstract FileDescriptor createFd(); - - /** - * Implementations MUST return the bytes read or throw an Exception. - * - * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or - * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer - * contents and respectively wait for further input or retry the read immediately. For all other - * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this - * method. - */ - protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer) - throws Exception; - - /** - * Called by the main loop for every packet. Any desired copies of - * |recvbuf| should be made in here, as the underlying byte array is - * reused across all reads. - */ - protected void handlePacket(@NonNull BufferType recvbuf, int length) {} - - /** - * Called by the subclasses of FdEventsReader, decide whether it should stop reading packet or - * just ignore the specific error other than EAGAIN or EINTR. - * - * @return {@code true} if this FdEventsReader should stop reading from the socket. - * {@code false} if it should continue. - */ - protected boolean handleReadError(@NonNull ErrnoException e) { - logError("readPacket error: ", e); - return true; // by default, stop reading on any error. - } - - /** - * Called by the subclasses of FdEventsReader, decide whether it should stop reading from the - * socket or process the packet and continue to read upon receiving a zero-length packet. - * - * @return {@code true} if this FdEventsReader should process the zero-length packet. - * {@code false} if it should stop reading from the socket. - */ - protected boolean shouldProcessZeroLengthPacket() { - return false; // by default, stop reading upon receiving zero-length packet. - } - - /** - * Called by the main loop to log errors. In some cases |e| may be null. - */ - protected void logError(@NonNull String msg, @Nullable Exception e) {} - - /** - * Called by start(), if successful, just prior to returning. - */ - protected void onStart() {} - - /** - * Called by stop() just prior to returning. - */ - protected void onStop() {} - - private boolean createAndRegisterFd() { - if (mFd != null) return true; - - try { - mFd = createFd(); - } catch (Exception e) { - logError("Failed to create socket: ", e); - closeFd(mFd); - mFd = null; - } - - if (mFd == null) return false; - - getMessageQueue().addOnFileDescriptorEventListener( - mFd, - FD_EVENTS, - (fd, events) -> { - // Always call handleInput() so read/recvfrom are given - // a proper chance to encounter a meaningful errno and - // perhaps log a useful error message. - if (!isRunning() || !handleInput()) { - unregisterAndDestroyFd(); - return UNREGISTER_THIS_FD; - } - return FD_EVENTS; - }); - onStart(); - return true; - } - - protected boolean isRunning() { - return (mFd != null) && mFd.valid(); - } - - // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error. - private boolean handleInput() { - while (isRunning()) { - final int bytesRead; - - try { - bytesRead = readPacket(mFd, mBuffer); - if (bytesRead == 0 && !shouldProcessZeroLengthPacket()) { - if (isRunning()) logError("Socket closed, exiting", null); - break; - } - mPacketsReceived++; - } catch (ErrnoException e) { - if (e.errno == OsConstants.EAGAIN) { - // We've read everything there is to read this time around. - return true; - } else if (e.errno == OsConstants.EINTR) { - continue; - } else { - if (!isRunning()) break; - final boolean shouldStop = handleReadError(e); - if (shouldStop) break; - continue; - } - } catch (Exception e) { - if (isRunning()) logError("readPacket error: ", e); - break; - } - - try { - handlePacket(mBuffer, bytesRead); - } catch (Exception e) { - logError("handlePacket error: ", e); - Log.wtf(TAG, "Error handling packet", e); - } - } - - return false; - } - - private void unregisterAndDestroyFd() { - if (mFd == null) return; - - getMessageQueue().removeOnFileDescriptorEventListener(mFd); - closeFd(mFd); - mFd = null; - onStop(); - } - - private boolean onCorrectThread() { - return (mHandler.getLooper() == Looper.myLooper()); - } -} diff --git a/common/device/com/android/net/module/util/FeatureVersions.java b/common/device/com/android/net/module/util/FeatureVersions.java deleted file mode 100644 index 149756c3..00000000 --- a/common/device/com/android/net/module/util/FeatureVersions.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util; - -/** - * Class to centralize feature version control that requires a specific module or a specific - * module version. - * @hide - */ -public class FeatureVersions { - /** - * This constant is used to do bitwise shift operation to create module ids. - * The module version is composed with 9 digits which is placed in the lower 36 bits. - */ - private static final int MODULE_SHIFT = 36; - /** - * The bitmask to do bitwise-and(i.e. {@code &}) operation to get the module id. - */ - public static final long MODULE_MASK = 0xFF0_0000_0000L; - /** - * The bitmask to do bitwise-and(i.e. {@code &}) operation to get the module version. - */ - public static final long VERSION_MASK = 0x00F_FFFF_FFFFL; - public static final long CONNECTIVITY_MODULE_ID = 0x01L << MODULE_SHIFT; - public static final long NETWORK_STACK_MODULE_ID = 0x02L << MODULE_SHIFT; - // CLAT_ADDRESS_TRANSLATE is a feature of the network stack, which doesn't throw when system - // try to add a NAT-T keepalive packet filter with v6 address, introduced in version - // M-2023-Sept on July 3rd, 2023. - public static final long FEATURE_CLAT_ADDRESS_TRANSLATE = - NETWORK_STACK_MODULE_ID + 34_09_00_000L; -} diff --git a/common/device/com/android/net/module/util/IBpfMap.java b/common/device/com/android/net/module/util/IBpfMap.java deleted file mode 100644 index 83ff875c..00000000 --- a/common/device/com/android/net/module/util/IBpfMap.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import android.system.ErrnoException; - -import androidx.annotation.NonNull; - -import java.io.IOException; -import java.util.NoSuchElementException; - -/** - * The interface of BpfMap. This could be used to inject for testing. - * So the testing code won't load the JNI and update the entries to kernel. - * - * @param <K> the key of the map. - * @param <V> the value of the map. - */ -public interface IBpfMap<K extends Struct, V extends Struct> extends AutoCloseable { - /** Update an existing or create a new key -> value entry in an eBbpf map. */ - void updateEntry(K key, V value) throws ErrnoException; - - /** If the key does not exist in the map, insert key -> value entry into eBpf map. */ - void insertEntry(K key, V value) throws ErrnoException, IllegalStateException; - - /** If the key already exists in the map, replace its value. */ - void replaceEntry(K key, V value) throws ErrnoException, NoSuchElementException; - - /** - * Update an existing or create a new key -> value entry in an eBbpf map. Returns true if - * inserted, false if replaced. (use updateEntry() if you don't care whether insert or replace - * happened). - */ - boolean insertOrReplaceEntry(K key, V value) throws ErrnoException; - - /** Remove existing key from eBpf map. Return true if something was deleted. */ - boolean deleteEntry(K key) throws ErrnoException; - - /** Returns {@code true} if this map contains no elements. */ - boolean isEmpty() throws ErrnoException; - - /** Get the key after the passed-in key. */ - K getNextKey(@NonNull K key) throws ErrnoException; - - /** Get the first key of the eBpf map. */ - K getFirstKey() throws ErrnoException; - - /** Check whether a key exists in the map. */ - boolean containsKey(@NonNull K key) throws ErrnoException; - - /** Retrieve a value from the map. */ - V getValue(@NonNull K key) throws ErrnoException; - - public interface ThrowingBiConsumer<T,U> { - void accept(T t, U u) throws ErrnoException; - } - - /** - * Iterate through the map and handle each key -> value retrieved base on the given BiConsumer. - */ - void forEach(ThrowingBiConsumer<K, V> action) throws ErrnoException; - - /** Clears the map. */ - void clear() throws ErrnoException; - - /** Close for AutoCloseable. */ - @Override - void close() throws IOException; -} diff --git a/common/device/com/android/net/module/util/Ipv6Utils.java b/common/device/com/android/net/module/util/Ipv6Utils.java deleted file mode 100644 index d5382215..00000000 --- a/common/device/com/android/net/module/util/Ipv6Utils.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util; - -import static android.system.OsConstants.IPPROTO_ICMPV6; - -import static com.android.net.module.util.IpUtils.icmpv6Checksum; -import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REPLY_TYPE; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; - -import android.net.MacAddress; - -import com.android.net.module.util.structs.EthernetHeader; -import com.android.net.module.util.structs.Icmpv6Header; -import com.android.net.module.util.structs.Ipv6Header; -import com.android.net.module.util.structs.NaHeader; -import com.android.net.module.util.structs.NsHeader; -import com.android.net.module.util.structs.RaHeader; -import com.android.net.module.util.structs.RsHeader; - -import java.net.Inet6Address; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * Utilities for IPv6 packets. - */ -public class Ipv6Utils { - /** - * Build a generic ICMPv6 packet without Ethernet header. - */ - public static ByteBuffer buildIcmpv6Packet(final Inet6Address srcIp, final Inet6Address dstIp, - short type, short code, final ByteBuffer... options) { - final int ipv6HeaderLen = Struct.getSize(Ipv6Header.class); - final int icmpv6HeaderLen = Struct.getSize(Icmpv6Header.class); - int payloadLen = 0; - for (ByteBuffer option: options) { - payloadLen += option.limit(); - } - final ByteBuffer packet = ByteBuffer.allocate(ipv6HeaderLen + icmpv6HeaderLen + payloadLen); - final Ipv6Header ipv6Header = - new Ipv6Header((int) 0x60000000 /* version, traffic class, flowlabel */, - icmpv6HeaderLen + payloadLen /* payload length */, - (byte) IPPROTO_ICMPV6 /* next header */, (byte) 0xff /* hop limit */, srcIp, dstIp); - final Icmpv6Header icmpv6Header = new Icmpv6Header(type, code, (short) 0 /* checksum */); - - ipv6Header.writeToByteBuffer(packet); - icmpv6Header.writeToByteBuffer(packet); - for (ByteBuffer option : options) { - packet.put(option); - // in case option might be reused by caller, restore the position and - // limit of bytebuffer. - option.clear(); - } - packet.flip(); - - // Populate the ICMPv6 checksum field. - packet.putShort(ipv6HeaderLen + 2, icmpv6Checksum(packet, 0 /* ipOffset */, - ipv6HeaderLen /* transportOffset */, - (short) (icmpv6HeaderLen + payloadLen) /* transportLen */)); - return packet; - - } - - /** - * Build a generic ICMPv6 packet(e.g., packet used in the neighbor discovery protocol). - */ - public static ByteBuffer buildIcmpv6Packet(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, short type, short code, - final ByteBuffer... options) { - final ByteBuffer payload = buildIcmpv6Packet(srcIp, dstIp, type, code, options); - - final int etherHeaderLen = Struct.getSize(EthernetHeader.class); - final ByteBuffer packet = ByteBuffer.allocate(etherHeaderLen + payload.limit()); - final EthernetHeader ethHeader = - new EthernetHeader(dstMac, srcMac, (short) ETHER_TYPE_IPV6); - - ethHeader.writeToByteBuffer(packet); - packet.put(payload); - packet.flip(); - - return packet; - } - - /** - * Build the ICMPv6 packet payload including payload header and specific options. - */ - private static ByteBuffer[] buildIcmpv6Payload(final ByteBuffer payloadHeader, - final ByteBuffer... options) { - final ByteBuffer[] payload = new ByteBuffer[options.length + 1]; - payload[0] = payloadHeader; - System.arraycopy(options, 0, payload, 1, options.length); - return payload; - } - - /** - * Build an ICMPv6 Router Advertisement packet from the required specified parameters. - */ - public static ByteBuffer buildRaPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final byte flags, - final int lifetime, final long reachableTime, final long retransTimer, - final ByteBuffer... options) { - final RaHeader raHeader = new RaHeader((byte) 0 /* hopLimit, unspecified */, - flags, lifetime, reachableTime, retransTimer); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(raHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_ROUTER_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Neighbor Advertisement packet from the required specified parameters. - */ - public static ByteBuffer buildNaPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final int flags, - final Inet6Address target, final ByteBuffer... options) { - final NaHeader naHeader = new NaHeader(flags, target); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(naHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_NEIGHBOR_ADVERTISEMENT /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Neighbor Solicitation packet from the required specified parameters. - */ - public static ByteBuffer buildNsPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, - final Inet6Address target, final ByteBuffer... options) { - final NsHeader nsHeader = new NsHeader(target); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(nsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_NEIGHBOR_SOLICITATION /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Router Solicitation packet from the required specified parameters. - */ - public static ByteBuffer buildRsPacket(final MacAddress srcMac, final MacAddress dstMac, - final Inet6Address srcIp, final Inet6Address dstIp, final ByteBuffer... options) { - final RsHeader rsHeader = new RsHeader((int) 0 /* reserved */); - final ByteBuffer[] payload = buildIcmpv6Payload( - ByteBuffer.wrap(rsHeader.writeToBytes(ByteOrder.BIG_ENDIAN)), options); - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_ROUTER_SOLICITATION /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Echo Request packet from the required specified parameters. - */ - public static ByteBuffer buildEchoRequestPacket(final MacAddress srcMac, - final MacAddress dstMac, final Inet6Address srcIp, final Inet6Address dstIp) { - final ByteBuffer payload = ByteBuffer.allocate(4); // ID and Sequence number may be zero. - return buildIcmpv6Packet(srcMac, dstMac, srcIp, dstIp, - (byte) ICMPV6_ECHO_REQUEST_TYPE /* type */, (byte) 0 /* code */, payload); - } - - /** - * Build an ICMPv6 Echo Reply packet without ethernet header. - */ - public static ByteBuffer buildEchoReplyPacket(final Inet6Address srcIp, - final Inet6Address dstIp) { - final ByteBuffer payload = ByteBuffer.allocate(4); // ID and Sequence number may be zero. - return buildIcmpv6Packet(srcIp, dstIp, (byte) ICMPV6_ECHO_REPLY_TYPE /* type */, - (byte) 0 /* code */, payload); - } -} diff --git a/common/device/com/android/net/module/util/JniUtil.java b/common/device/com/android/net/module/util/JniUtil.java deleted file mode 100644 index 5210a3ef..00000000 --- a/common/device/com/android/net/module/util/JniUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util; - -/** - * Utilities for modules to use jni. - */ -public final class JniUtil { - /** - * The method to find jni library accroding to the giving package name. - * - * The jni library name would be packageName + _jni.so. E.g. - * com_android_networkstack_tethering_util_jni for tethering, - * com_android_connectivity_util_jni for connectivity. - */ - public static String getJniLibraryName(final Package pkg) { - final String libPrefix = pkg.getName().replaceAll("\\.", "_"); - - return libPrefix + "_jni"; - } -} diff --git a/common/device/com/android/net/module/util/NetworkMonitorUtils.java b/common/device/com/android/net/module/util/NetworkMonitorUtils.java deleted file mode 100644 index 5a4412f5..00000000 --- a/common/device/com/android/net/module/util/NetworkMonitorUtils.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; -import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; -import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; -import static android.net.NetworkCapabilities.TRANSPORT_WIFI; - -import android.annotation.NonNull; -import android.net.NetworkCapabilities; -import android.os.Build; - -/** @hide */ -public class NetworkMonitorUtils { - // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use - // NetworkStack shims, but at the same time cannot use non-system APIs. - // TRANSPORT_TEST is test API as of R (so it is enforced to always be 7 and can't be changed), - // and it is being added as a system API in S. - // TODO: use NetworkCapabilities.TRANSPORT_TEST once NetworkStack builds against API 31. - private static final int TRANSPORT_TEST = 7; - - // This class is used by both NetworkMonitor and ConnectivityService, so it cannot use - // NetworkStack shims, but at the same time cannot use non-system APIs. - // NET_CAPABILITY_NOT_VCN_MANAGED is system API as of S (so it is enforced to always be 28 and - // can't be changed). - // TODO: use NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED once NetworkStack builds against - // API 31. - public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; - - // Network conditions broadcast constants - public static final String ACTION_NETWORK_CONDITIONS_MEASURED = - "android.net.conn.NETWORK_CONDITIONS_MEASURED"; - public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; - public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; - public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; - public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; - public static final String EXTRA_CELL_ID = "extra_cellid"; - public static final String EXTRA_SSID = "extra_ssid"; - public static final String EXTRA_BSSID = "extra_bssid"; - /** real time since boot */ - public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; - public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; - public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = - "android.permission.ACCESS_NETWORK_CONDITIONS"; - - /** - * Return whether validation is required for private DNS in strict mode. - * @param nc Network capabilities of the network to test. - */ - public static boolean isPrivateDnsValidationRequired(@NonNull final NetworkCapabilities nc) { - final boolean isVcnManaged = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) - && !nc.hasCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - final boolean isOemPaid = nc.hasCapability(NET_CAPABILITY_OEM_PAID) - && nc.hasCapability(NET_CAPABILITY_TRUSTED); - final boolean isDefaultCapable = nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasCapability(NET_CAPABILITY_TRUSTED); - - // TODO: Consider requiring validation for DUN networks. - if (nc.hasCapability(NET_CAPABILITY_INTERNET) - && (isVcnManaged || isOemPaid || isDefaultCapable)) { - return true; - } - - // Test networks that also have one of the major transport types are attempting to replicate - // that transport on a test interface (for example, test ethernet networks with - // EthernetManager#setIncludeTestInterfaces). Run validation on them for realistic tests. - // See also comments on EthernetManager#setIncludeTestInterfaces and on TestNetworkManager. - if (nc.hasTransport(TRANSPORT_TEST) && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) && ( - nc.hasTransport(TRANSPORT_WIFI) - || nc.hasTransport(TRANSPORT_CELLULAR) - || nc.hasTransport(TRANSPORT_BLUETOOTH) - || nc.hasTransport(TRANSPORT_ETHERNET))) { - return true; - } - - return false; - } - - /** - * Return whether validation is required for a network. - * @param isVpnValidationRequired Whether network validation should be performed for VPN - * networks. - * @param nc Network capabilities of the network to test. - */ - public static boolean isValidationRequired(boolean isDunValidationRequired, - boolean isVpnValidationRequired, - @NonNull final NetworkCapabilities nc) { - if (isDunValidationRequired && nc.hasCapability(NET_CAPABILITY_DUN)) { - return true; - } - if (!nc.hasCapability(NET_CAPABILITY_NOT_VPN)) { - return isVpnValidationRequired; - } - return isPrivateDnsValidationRequired(nc); - } -} diff --git a/common/device/com/android/net/module/util/PacketBuilder.java b/common/device/com/android/net/module/util/PacketBuilder.java deleted file mode 100644 index 33e5bfad..00000000 --- a/common/device/com/android/net/module/util/PacketBuilder.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util; - -import static android.system.OsConstants.IPPROTO_IP; -import static android.system.OsConstants.IPPROTO_IPV6; -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; - -import static com.android.net.module.util.IpUtils.ipChecksum; -import static com.android.net.module.util.IpUtils.tcpChecksum; -import static com.android.net.module.util.IpUtils.udpChecksum; -import static com.android.net.module.util.NetworkStackConstants.IPV4_CHECKSUM_OFFSET; -import static com.android.net.module.util.NetworkStackConstants.IPV4_LENGTH_OFFSET; -import static com.android.net.module.util.NetworkStackConstants.IPV6_HEADER_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV6_LEN_OFFSET; -import static com.android.net.module.util.NetworkStackConstants.TCP_CHECKSUM_OFFSET; -import static com.android.net.module.util.NetworkStackConstants.UDP_CHECKSUM_OFFSET; -import static com.android.net.module.util.NetworkStackConstants.UDP_LENGTH_OFFSET; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.structs.EthernetHeader; -import com.android.net.module.util.structs.Ipv4Header; -import com.android.net.module.util.structs.Ipv6Header; -import com.android.net.module.util.structs.TcpHeader; -import com.android.net.module.util.structs.UdpHeader; - -import java.io.IOException; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; - -/** - * The class is used to build a packet. - * - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 2 header (EthernetHeader) | (optional) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 3 header (Ipv4Header, Ipv6Header) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Layer 4 header (TcpHeader, UdpHeader) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Payload | (optional) - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Below is a sample code to build a packet. - * - * // Initialize builder - * final ByteBuffer buf = ByteBuffer.allocate(...); - * final PacketBuilder pb = new PacketBuilder(buf); - * // Write headers - * pb.writeL2Header(...); - * pb.writeIpHeader(...); - * pb.writeTcpHeader(...); - * // Write payload - * buf.putInt(...); - * buf.putShort(...); - * buf.putByte(...); - * // Finalize and use the packet - * pb.finalizePacket(); - * sendPacket(buf); - */ -public class PacketBuilder { - private static final int INVALID_OFFSET = -1; - - private final ByteBuffer mBuffer; - - private int mIpv4HeaderOffset = INVALID_OFFSET; - private int mIpv6HeaderOffset = INVALID_OFFSET; - private int mTcpHeaderOffset = INVALID_OFFSET; - private int mUdpHeaderOffset = INVALID_OFFSET; - - public PacketBuilder(@NonNull ByteBuffer buffer) { - mBuffer = buffer; - } - - /** - * Write an ethernet header. - * - * @param srcMac source MAC address - * @param dstMac destination MAC address - * @param etherType ether type - */ - public void writeL2Header(MacAddress srcMac, MacAddress dstMac, short etherType) throws - IOException { - final EthernetHeader ethHeader = new EthernetHeader(dstMac, srcMac, etherType); - try { - ethHeader.writeToByteBuffer(mBuffer); - } catch (IllegalArgumentException | BufferOverflowException e) { - throw new IOException("Error writing to buffer: ", e); - } - } - - /** - * Write an IPv4 header. - * The IP header length and checksum are calculated and written back in #finalizePacket. - * - * @param tos type of service - * @param id the identification - * @param flagsAndFragmentOffset flags and fragment offset - * @param ttl time to live - * @param protocol protocol - * @param srcIp source IP address - * @param dstIp destination IP address - */ - public void writeIpv4Header(byte tos, short id, short flagsAndFragmentOffset, byte ttl, - byte protocol, @NonNull final Inet4Address srcIp, @NonNull final Inet4Address dstIp) - throws IOException { - mIpv4HeaderOffset = mBuffer.position(); - final Ipv4Header ipv4Header = new Ipv4Header(tos, - (short) 0 /* totalLength, calculate in #finalizePacket */, id, - flagsAndFragmentOffset, ttl, protocol, - (short) 0 /* checksum, calculate in #finalizePacket */, srcIp, dstIp); - - try { - ipv4Header.writeToByteBuffer(mBuffer); - } catch (IllegalArgumentException | BufferOverflowException e) { - throw new IOException("Error writing to buffer: ", e); - } - } - - /** - * Write an IPv6 header. - * The IP header length is calculated and written back in #finalizePacket. - * - * @param vtf version, traffic class and flow label - * @param nextHeader the transport layer protocol - * @param hopLimit hop limit - * @param srcIp source IP address - * @param dstIp destination IP address - */ - public void writeIpv6Header(int vtf, byte nextHeader, short hopLimit, - @NonNull final Inet6Address srcIp, @NonNull final Inet6Address dstIp) - throws IOException { - mIpv6HeaderOffset = mBuffer.position(); - final Ipv6Header ipv6Header = new Ipv6Header(vtf, - (short) 0 /* payloadLength, calculate in #finalizePacket */, nextHeader, - hopLimit, srcIp, dstIp); - - try { - ipv6Header.writeToByteBuffer(mBuffer); - } catch (IllegalArgumentException | BufferOverflowException e) { - throw new IOException("Error writing to buffer: ", e); - } - } - - /** - * Write a TCP header. - * The TCP header checksum is calculated and written back in #finalizePacket. - * - * @param srcPort source port - * @param dstPort destination port - * @param seq sequence number - * @param ack acknowledgement number - * @param tcpFlags tcp flags - * @param window window size - * @param urgentPointer urgent pointer - */ - public void writeTcpHeader(short srcPort, short dstPort, short seq, short ack, - byte tcpFlags, short window, short urgentPointer) throws IOException { - mTcpHeaderOffset = mBuffer.position(); - final TcpHeader tcpHeader = new TcpHeader(srcPort, dstPort, seq, ack, - (short) ((short) 0x5000 | ((byte) 0x3f & tcpFlags)) /* dataOffsetAndControlBits, - dataOffset is always 5(*4bytes) because options not supported */, window, - (short) 0 /* checksum, calculate in #finalizePacket */, - urgentPointer); - - try { - tcpHeader.writeToByteBuffer(mBuffer); - } catch (IllegalArgumentException | BufferOverflowException e) { - throw new IOException("Error writing to buffer: ", e); - } - } - - /** - * Write a UDP header. - * The UDP header length and checksum are calculated and written back in #finalizePacket. - * - * @param srcPort source port - * @param dstPort destination port - */ - public void writeUdpHeader(short srcPort, short dstPort) throws IOException { - mUdpHeaderOffset = mBuffer.position(); - final UdpHeader udpHeader = new UdpHeader(srcPort, dstPort, - (short) 0 /* length, calculate in #finalizePacket */, - (short) 0 /* checksum, calculate in #finalizePacket */); - - try { - udpHeader.writeToByteBuffer(mBuffer); - } catch (IllegalArgumentException | BufferOverflowException e) { - throw new IOException("Error writing to buffer: ", e); - } - } - - /** - * Finalize the packet. - * - * Call after writing L4 header (no payload) or payload to the buffer used by the builder. - * L3 header length, L3 header checksum and L4 header checksum are calculated and written back - * after finalization. - */ - @NonNull - public ByteBuffer finalizePacket() throws IOException { - // [1] Finalize IPv4 or IPv6 header. - int ipHeaderOffset = INVALID_OFFSET; - if (mIpv4HeaderOffset != INVALID_OFFSET) { - ipHeaderOffset = mIpv4HeaderOffset; - - // Populate the IPv4 totalLength field. - mBuffer.putShort(mIpv4HeaderOffset + IPV4_LENGTH_OFFSET, - (short) (mBuffer.position() - mIpv4HeaderOffset)); - - // Populate the IPv4 header checksum field. - mBuffer.putShort(mIpv4HeaderOffset + IPV4_CHECKSUM_OFFSET, - ipChecksum(mBuffer, mIpv4HeaderOffset /* headerOffset */)); - } else if (mIpv6HeaderOffset != INVALID_OFFSET) { - ipHeaderOffset = mIpv6HeaderOffset; - - // Populate the IPv6 payloadLength field. - // The payload length doesn't include IPv6 header length. See rfc8200 section 3. - mBuffer.putShort(mIpv6HeaderOffset + IPV6_LEN_OFFSET, - (short) (mBuffer.position() - mIpv6HeaderOffset - IPV6_HEADER_LEN)); - } else { - throw new IOException("Packet is missing neither IPv4 nor IPv6 header"); - } - - // [2] Finalize TCP or UDP header. - if (mTcpHeaderOffset != INVALID_OFFSET) { - // Populate the TCP header checksum field. - mBuffer.putShort(mTcpHeaderOffset + TCP_CHECKSUM_OFFSET, tcpChecksum(mBuffer, - ipHeaderOffset /* ipOffset */, mTcpHeaderOffset /* transportOffset */, - mBuffer.position() - mTcpHeaderOffset /* transportLen */)); - } else if (mUdpHeaderOffset != INVALID_OFFSET) { - // Populate the UDP header length field. - mBuffer.putShort(mUdpHeaderOffset + UDP_LENGTH_OFFSET, - (short) (mBuffer.position() - mUdpHeaderOffset)); - - // Populate the UDP header checksum field. - mBuffer.putShort(mUdpHeaderOffset + UDP_CHECKSUM_OFFSET, udpChecksum(mBuffer, - ipHeaderOffset /* ipOffset */, mUdpHeaderOffset /* transportOffset */)); - } else { - throw new IOException("Packet is missing neither TCP nor UDP header"); - } - - mBuffer.flip(); - return mBuffer; - } - - /** - * Allocate bytebuffer for building the packet. - * - * @param hasEther has ethernet header. Set this flag to indicate that the packet has an - * ethernet header. - * @param l3proto the layer 3 protocol. Only {@code IPPROTO_IP} and {@code IPPROTO_IPV6} - * currently supported. - * @param l4proto the layer 4 protocol. Only {@code IPPROTO_TCP} and {@code IPPROTO_UDP} - * currently supported. - * @param payloadLen length of the payload. - */ - @NonNull - public static ByteBuffer allocate(boolean hasEther, int l3proto, int l4proto, int payloadLen) { - if (l3proto != IPPROTO_IP && l3proto != IPPROTO_IPV6) { - throw new IllegalArgumentException("Unsupported layer 3 protocol " + l3proto); - } - - if (l4proto != IPPROTO_TCP && l4proto != IPPROTO_UDP) { - throw new IllegalArgumentException("Unsupported layer 4 protocol " + l4proto); - } - - if (payloadLen < 0) { - throw new IllegalArgumentException("Invalid payload length " + payloadLen); - } - - int packetLen = 0; - if (hasEther) packetLen += Struct.getSize(EthernetHeader.class); - packetLen += (l3proto == IPPROTO_IP) ? Struct.getSize(Ipv4Header.class) - : Struct.getSize(Ipv6Header.class); - packetLen += (l4proto == IPPROTO_TCP) ? Struct.getSize(TcpHeader.class) - : Struct.getSize(UdpHeader.class); - packetLen += payloadLen; - - return ByteBuffer.allocate(packetLen); - } -} diff --git a/common/device/com/android/net/module/util/PacketReader.java b/common/device/com/android/net/module/util/PacketReader.java deleted file mode 100644 index 66c47888..00000000 --- a/common/device/com/android/net/module/util/PacketReader.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 com.android.net.module.util; - -import static java.lang.Math.max; - -import android.os.Handler; -import android.system.Os; - -import java.io.FileDescriptor; - -/** - * Specialization of {@link FdEventsReader} that reads packets into a byte array. - * - * TODO: rename this class to something more correctly descriptive (something - * like [or less horrible than] FdReadEventsHandler?). - */ -public abstract class PacketReader extends FdEventsReader<byte[]> { - - public static final int DEFAULT_RECV_BUF_SIZE = 2 * 1024; - - protected PacketReader(Handler h) { - this(h, DEFAULT_RECV_BUF_SIZE); - } - - protected PacketReader(Handler h, int recvBufSize) { - super(h, new byte[max(recvBufSize, DEFAULT_RECV_BUF_SIZE)]); - } - - @Override - protected final int recvBufSize(byte[] buffer) { - return buffer.length; - } - - /** - * Subclasses MAY override this to change the default read() implementation - * in favour of, say, recvfrom(). - * - * Implementations MUST return the bytes read or throw an Exception. - */ - @Override - protected int readPacket(FileDescriptor fd, byte[] packetBuffer) throws Exception { - return Os.read(fd, packetBuffer, 0, packetBuffer.length); - } -} diff --git a/common/device/com/android/net/module/util/SharedLog.java b/common/device/com/android/net/module/util/SharedLog.java deleted file mode 100644 index 6b12c80d..00000000 --- a/common/device/com/android/net/module/util/SharedLog.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.net.module.util; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.text.TextUtils; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.time.LocalDateTime; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; -import java.util.StringJoiner; - - -/** - * Class to centralize logging functionality for tethering. - * - * All access to class methods other than dump() must be on the same thread. - * - * @hide - */ -public class SharedLog { - private static final int DEFAULT_MAX_RECORDS = 500; - private static final String COMPONENT_DELIMITER = "."; - - private enum Category { - NONE, - ERROR, - MARK, - WARN, - VERBOSE, - TERRIBLE, - } - - private final LocalLog mLocalLog; - // The tag to use for output to the system log. This is not output to the - // LocalLog because that would be redundant. - private final String mTag; - // The component (or subcomponent) of a system that is sharing this log. - // This can grow in depth if components call forSubComponent() to obtain - // their SharedLog instance. The tag is not included in the component for - // brevity. - private final String mComponent; - - public SharedLog(String tag) { - this(DEFAULT_MAX_RECORDS, tag); - } - - public SharedLog(int maxRecords, String tag) { - this(new LocalLog(maxRecords), tag, tag); - } - - private SharedLog(LocalLog localLog, String tag, String component) { - mLocalLog = localLog; - mTag = tag; - mComponent = component; - } - - public String getTag() { - return mTag; - } - - /** - * Create a SharedLog based on this log with an additional component prefix on each logged line. - */ - public SharedLog forSubComponent(String component) { - if (!isRootLogInstance()) { - component = mComponent + COMPONENT_DELIMITER + component; - } - return new SharedLog(mLocalLog, mTag, component); - } - - /** - * Dump the contents of this log. - * - * <p>This method may be called on any thread. - */ - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - mLocalLog.dump(writer); - } - - /** - * Reverse dump the contents of this log. - * - * <p>This method may be called on any thread. - */ - public void reverseDump(PrintWriter writer) { - mLocalLog.reverseDump(writer); - } - - ////// - // Methods that both log an entry and emit it to the system log. - ////// - - /** - * Log an error due to an exception. This does not include the exception stacktrace. - * - * <p>The log entry will be also added to the system log. - * @see #e(String, Throwable) - */ - public void e(Exception e) { - Log.e(mTag, record(Category.ERROR, e.toString())); - } - - /** - * Log an error message. - * - * <p>The log entry will be also added to the system log. - */ - public void e(String msg) { - Log.e(mTag, record(Category.ERROR, msg)); - } - - /** - * Log an error due to an exception, with the exception stacktrace if provided. - * - * <p>The error and exception message appear in the shared log, but the stacktrace is only - * logged in general log output (logcat). The log entry will be also added to the system log. - */ - public void e(@NonNull String msg, @Nullable Throwable exception) { - if (exception == null) { - e(msg); - return; - } - Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception); - } - - /** - * Log an informational message. - * - * <p>The log entry will be also added to the system log. - */ - public void i(String msg) { - Log.i(mTag, record(Category.NONE, msg)); - } - - /** - * Log a warning message. - * - * <p>The log entry will be also added to the system log. - */ - public void w(String msg) { - Log.w(mTag, record(Category.WARN, msg)); - } - - /** - * Log a verbose message. - * - * <p>The log entry will be also added to the system log. - */ - public void v(String msg) { - Log.v(mTag, record(Category.VERBOSE, msg)); - } - - /** - * Log a terrible failure message. - * - * <p>The log entry will be also added to the system log and will trigger system reporting - * for terrible failures. - */ - public void wtf(String msg) { - Log.wtf(mTag, record(Category.TERRIBLE, msg)); - } - - /** - * Log a terrible failure due to an exception, with the exception stacktrace if provided. - * - * <p>The error and exception message appear in the shared log, but the stacktrace is only - * logged in general log output (logcat). The log entry will be also added to the system log - * and will trigger system reporting for terrible failures. - */ - public void wtf(@NonNull String msg, @Nullable Throwable exception) { - if (exception == null) { - e(msg); - return; - } - Log.wtf(mTag, record(Category.TERRIBLE, msg + ": " + exception.getMessage()), exception); - } - - - ////// - // Methods that only log an entry (and do NOT emit to the system log). - ////// - - /** - * Log a general message to be only included in the in-memory log. - * - * <p>The log entry will *not* be added to the system log. - */ - public void log(String msg) { - record(Category.NONE, msg); - } - - /** - * Log a general, formatted message to be only included in the in-memory log. - * - * <p>The log entry will *not* be added to the system log. - * @see String#format(String, Object...) - */ - public void logf(String fmt, Object... args) { - log(String.format(fmt, args)); - } - - /** - * Log a message with MARK level. - * - * <p>The log entry will *not* be added to the system log. - */ - public void mark(String msg) { - record(Category.MARK, msg); - } - - private String record(Category category, String msg) { - final String entry = logLine(category, msg); - mLocalLog.append(entry); - return entry; - } - - private String logLine(Category category, String msg) { - final StringJoiner sj = new StringJoiner(" "); - if (!isRootLogInstance()) sj.add("[" + mComponent + "]"); - if (category != Category.NONE) sj.add(category.toString()); - return sj.add(msg).toString(); - } - - // Check whether this SharedLog instance is nominally the top level in - // a potential hierarchy of shared logs (the root of a tree), - // or is a subcomponent within the hierarchy. - private boolean isRootLogInstance() { - return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag); - } - - private static final class LocalLog { - private final Deque<String> mLog; - private final int mMaxLines; - - LocalLog(int maxLines) { - mMaxLines = Math.max(0, maxLines); - mLog = new ArrayDeque<>(mMaxLines); - } - - synchronized void append(String logLine) { - if (mMaxLines <= 0) return; - while (mLog.size() >= mMaxLines) { - mLog.remove(); - } - mLog.add(LocalDateTime.now() + " - " + logLine); - } - - /** - * Dumps the content of local log to print writer with each log entry - * - * @param pw printer writer to write into - */ - synchronized void dump(PrintWriter pw) { - for (final String s : mLog) { - pw.println(s); - } - } - - synchronized void reverseDump(PrintWriter pw) { - final Iterator<String> itr = mLog.descendingIterator(); - while (itr.hasNext()) { - pw.println(itr.next()); - } - } - } -} diff --git a/common/device/com/android/net/module/util/SocketUtils.java b/common/device/com/android/net/module/util/SocketUtils.java deleted file mode 100644 index 9878ea5c..00000000 --- a/common/device/com/android/net/module/util/SocketUtils.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import static android.net.util.SocketUtils.closeSocket; - -import android.annotation.NonNull; -import android.system.NetlinkSocketAddress; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.SocketAddress; - -/** - * Collection of utilities to interact with raw sockets. - * - * This class also provides utilities to interact with {@link android.net.util.SocketUtils} - * because it is in the API surface could not be simply move the frameworks/libs/net/ - * to share with module. - * - * TODO: deprecate android.net.util.SocketUtils and replace with this class. - */ -public class SocketUtils { - - /** - * Make a socket address to communicate with netlink. - */ - @NonNull - public static SocketAddress makeNetlinkSocketAddress(int portId, int groupsMask) { - return new NetlinkSocketAddress(portId, groupsMask); - } - - /** - * Close a socket, ignoring any exception while closing. - */ - public static void closeSocketQuietly(FileDescriptor fd) { - try { - closeSocket(fd); - } catch (IOException ignored) { - } - } - - private SocketUtils() {} -} diff --git a/common/device/com/android/net/module/util/Struct.java b/common/device/com/android/net/module/util/Struct.java deleted file mode 100644 index b638a461..00000000 --- a/common/device/com/android/net/module/util/Struct.java +++ /dev/null @@ -1,774 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.math.BigInteger; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Define a generic class that helps to parse the structured message. - * - * Example usage: - * - * // C-style NduserOption message header definition in the kernel: - * struct nduseroptmsg { - * unsigned char nduseropt_family; - * unsigned char nduseropt_pad1; - * unsigned short nduseropt_opts_len; - * int nduseropt_ifindex; - * __u8 nduseropt_icmp_type; - * __u8 nduseropt_icmp_code; - * unsigned short nduseropt_pad2; - * unsigned int nduseropt_pad3; - * } - * - * - Declare a subclass with explicit constructor or not which extends from this class to parse - * NduserOption header from raw bytes array. - * - * - Option w/ explicit constructor: - * static class NduserOptHeaderMessage extends Struct { - * @Field(order = 0, type = Type.U8, padding = 1) - * final short family; - * @Field(order = 1, type = Type.U16) - * final int len; - * @Field(order = 2, type = Type.S32) - * final int ifindex; - * @Field(order = 3, type = Type.U8) - * final short type; - * @Field(order = 4, type = Type.U8, padding = 6) - * final short code; - * - * NduserOptHeaderMessage(final short family, final int len, final int ifindex, - * final short type, final short code) { - * this.family = family; - * this.len = len; - * this.ifindex = ifindex; - * this.type = type; - * this.code = code; - * } - * } - * - * - Option w/o explicit constructor: - * static class NduserOptHeaderMessage extends Struct { - * @Field(order = 0, type = Type.U8, padding = 1) - * short family; - * @Field(order = 1, type = Type.U16) - * int len; - * @Field(order = 2, type = Type.S32) - * int ifindex; - * @Field(order = 3, type = Type.U8) - * short type; - * @Field(order = 4, type = Type.U8, padding = 6) - * short code; - * } - * - * - Parse the target message and refer the members. - * final ByteBuffer buf = ByteBuffer.wrap(RAW_BYTES_ARRAY); - * buf.order(ByteOrder.nativeOrder()); - * final NduserOptHeaderMessage nduserHdrMsg = Struct.parse(NduserOptHeaderMessage.class, buf); - * assertEquals(10, nduserHdrMsg.family); - */ -public class Struct { - public enum Type { - U8, // unsigned byte, size = 1 byte - U16, // unsigned short, size = 2 bytes - U32, // unsigned int, size = 4 bytes - U63, // unsigned long(MSB: 0), size = 8 bytes - U64, // unsigned long, size = 8 bytes - S8, // signed byte, size = 1 byte - S16, // signed short, size = 2 bytes - S32, // signed int, size = 4 bytes - S64, // signed long, size = 8 bytes - UBE16, // unsigned short in network order, size = 2 bytes - UBE32, // unsigned int in network order, size = 4 bytes - UBE63, // unsigned long(MSB: 0) in network order, size = 8 bytes - UBE64, // unsigned long in network order, size = 8 bytes - ByteArray, // byte array with predefined length - EUI48, // IEEE Extended Unique Identifier, a 48-bits long MAC address in network order - Ipv4Address, // IPv4 address in network order - Ipv6Address, // IPv6 address in network order - } - - /** - * Indicate that the field marked with this annotation will automatically be managed by this - * class (e.g., will be parsed by #parse). - * - * order: The placeholder associated with each field, consecutive order starting from zero. - * type: The primitive data type listed in above Type enumeration. - * padding: Padding bytes appear after the field for alignment. - * arraysize: The length of byte array. - * - * Annotation associated with field MUST have order and type properties at least, padding - * and arraysize properties depend on the specific usage, if these properties are absent, - * then default value 0 will be applied. - */ - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.FIELD) - public @interface Field { - int order(); - Type type(); - int padding() default 0; - int arraysize() default 0; - } - - private static class FieldInfo { - @NonNull - public final Field annotation; - @NonNull - public final java.lang.reflect.Field field; - - FieldInfo(final Field annotation, final java.lang.reflect.Field field) { - this.annotation = annotation; - this.field = field; - } - } - private static ConcurrentHashMap<Class, FieldInfo[]> sFieldCache = new ConcurrentHashMap(); - - private static void checkAnnotationType(final Field annotation, final Class fieldType) { - switch (annotation.type()) { - case U8: - case S16: - if (fieldType == Short.TYPE) return; - break; - case U16: - case S32: - case UBE16: - if (fieldType == Integer.TYPE) return; - break; - case U32: - case U63: - case S64: - case UBE32: - case UBE63: - if (fieldType == Long.TYPE) return; - break; - case U64: - case UBE64: - if (fieldType == BigInteger.class) return; - break; - case S8: - if (fieldType == Byte.TYPE) return; - break; - case ByteArray: - if (fieldType != byte[].class) break; - if (annotation.arraysize() <= 0) { - throw new IllegalArgumentException("Invalid ByteArray size: " - + annotation.arraysize()); - } - return; - case EUI48: - if (fieldType == MacAddress.class) return; - break; - case Ipv4Address: - if (fieldType == Inet4Address.class) return; - break; - case Ipv6Address: - if (fieldType == Inet6Address.class) return; - break; - default: - throw new IllegalArgumentException("Unknown type" + annotation.type()); - } - throw new IllegalArgumentException("Invalid primitive data type: " + fieldType - + " for annotation type: " + annotation.type()); - } - - private static int getFieldLength(final Field annotation) { - int length = 0; - switch (annotation.type()) { - case U8: - case S8: - length = 1; - break; - case U16: - case S16: - case UBE16: - length = 2; - break; - case U32: - case S32: - case UBE32: - length = 4; - break; - case U63: - case U64: - case S64: - case UBE63: - case UBE64: - length = 8; - break; - case ByteArray: - length = annotation.arraysize(); - break; - case EUI48: - length = 6; - break; - case Ipv4Address: - length = 4; - break; - case Ipv6Address: - length = 16; - break; - default: - throw new IllegalArgumentException("Unknown type" + annotation.type()); - } - return length + annotation.padding(); - } - - private static boolean isStructSubclass(final Class clazz) { - return clazz != null && Struct.class.isAssignableFrom(clazz) && Struct.class != clazz; - } - - private static int getAnnotationFieldCount(final Class clazz) { - int count = 0; - for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { - if (field.isAnnotationPresent(Field.class)) count++; - } - return count; - } - - private static boolean allFieldsFinal(final FieldInfo[] fields, boolean immutable) { - for (FieldInfo fi : fields) { - if (Modifier.isFinal(fi.field.getModifiers()) != immutable) return false; - } - return true; - } - - private static boolean hasBothMutableAndImmutableFields(final FieldInfo[] fields) { - return !allFieldsFinal(fields, true /* immutable */) - && !allFieldsFinal(fields, false /* mutable */); - } - - private static boolean matchConstructor(final Constructor cons, final FieldInfo[] fields) { - final Class[] paramTypes = cons.getParameterTypes(); - if (paramTypes.length != fields.length) return false; - for (int i = 0; i < paramTypes.length; i++) { - if (!paramTypes[i].equals(fields[i].field.getType())) return false; - } - return true; - } - - /** - * Read U64/UBE64 type data from ByteBuffer and output a BigInteger instance. - * - * @param buf The byte buffer to read. - * @param type The annotation type. - * - * The magnitude argument of BigInteger constructor is a byte array in big-endian order. - * If BigInteger data is read from the byte buffer in little-endian, reverse the order of - * the bytes is required; if BigInteger data is read from the byte buffer in big-endian, - * then just keep it as-is. - */ - private static BigInteger readBigInteger(final ByteBuffer buf, final Type type) { - final byte[] input = new byte[8]; - boolean reverseBytes = (type == Type.U64 && buf.order() == ByteOrder.LITTLE_ENDIAN); - for (int i = 0; i < 8; i++) { - input[reverseBytes ? input.length - 1 - i : i] = buf.get(); - } - return new BigInteger(1, input); - } - - /** - * Get the last 8 bytes of a byte array. If there are less than 8 bytes, - * the first bytes are replaced with zeroes. - */ - private static byte[] getLast8Bytes(final byte[] input) { - final byte[] tmp = new byte[8]; - System.arraycopy( - input, - Math.max(0, input.length - 8), // srcPos: read at most last 8 bytes - tmp, - Math.max(0, 8 - input.length), // dstPos: pad output with that many zeroes - Math.min(8, input.length)); // length - return tmp; - } - - /** - * Convert U64/UBE64 type data interpreted by BigInteger class to bytes array, output are - * always 8 bytes. - * - * @param bigInteger The number to convert. - * @param order Indicate ByteBuffer is read as little-endian or big-endian. - * @param type The annotation U64 type. - * - * BigInteger#toByteArray returns a byte array containing the 2's complement representation - * of this BigInteger, in big-endian. If annotation type is U64 and ByteBuffer is read as - * little-endian, then reversing the order of the bytes is required. - */ - private static byte[] bigIntegerToU64Bytes(final BigInteger bigInteger, final ByteOrder order, - final Type type) { - final byte[] bigIntegerBytes = bigInteger.toByteArray(); - final byte[] output = getLast8Bytes(bigIntegerBytes); - - if (type == Type.U64 && order == ByteOrder.LITTLE_ENDIAN) { - for (int i = 0; i < 4; i++) { - byte tmp = output[i]; - output[i] = output[7 - i]; - output[7 - i] = tmp; - } - } - return output; - } - - private static Object getFieldValue(final ByteBuffer buf, final FieldInfo fieldInfo) - throws BufferUnderflowException { - final Object value; - checkAnnotationType(fieldInfo.annotation, fieldInfo.field.getType()); - switch (fieldInfo.annotation.type()) { - case U8: - value = (short) (buf.get() & 0xFF); - break; - case U16: - value = (int) (buf.getShort() & 0xFFFF); - break; - case U32: - value = (long) (buf.getInt() & 0xFFFFFFFFL); - break; - case U64: - value = readBigInteger(buf, Type.U64); - break; - case S8: - value = buf.get(); - break; - case S16: - value = buf.getShort(); - break; - case S32: - value = buf.getInt(); - break; - case U63: - case S64: - value = buf.getLong(); - break; - case UBE16: - if (buf.order() == ByteOrder.LITTLE_ENDIAN) { - value = (int) (Short.reverseBytes(buf.getShort()) & 0xFFFF); - } else { - value = (int) (buf.getShort() & 0xFFFF); - } - break; - case UBE32: - if (buf.order() == ByteOrder.LITTLE_ENDIAN) { - value = (long) (Integer.reverseBytes(buf.getInt()) & 0xFFFFFFFFL); - } else { - value = (long) (buf.getInt() & 0xFFFFFFFFL); - } - break; - case UBE63: - if (buf.order() == ByteOrder.LITTLE_ENDIAN) { - value = Long.reverseBytes(buf.getLong()); - } else { - value = buf.getLong(); - } - break; - case UBE64: - value = readBigInteger(buf, Type.UBE64); - break; - case ByteArray: - final byte[] array = new byte[fieldInfo.annotation.arraysize()]; - buf.get(array); - value = array; - break; - case EUI48: - final byte[] macAddress = new byte[6]; - buf.get(macAddress); - value = MacAddress.fromBytes(macAddress); - break; - case Ipv4Address: - case Ipv6Address: - final boolean isIpv6 = (fieldInfo.annotation.type() == Type.Ipv6Address); - final byte[] address = new byte[isIpv6 ? 16 : 4]; - buf.get(address); - try { - value = InetAddress.getByAddress(address); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("illegal length of IP address", e); - } - break; - default: - throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); - } - - // Skip the padding data for alignment if any. - if (fieldInfo.annotation.padding() > 0) { - buf.position(buf.position() + fieldInfo.annotation.padding()); - } - return value; - } - - @Nullable - private Object getFieldValue(@NonNull java.lang.reflect.Field field) { - try { - return field.get(this); - } catch (IllegalAccessException e) { - throw new IllegalStateException("Cannot access field: " + field, e); - } - } - - private static void putFieldValue(final ByteBuffer output, final FieldInfo fieldInfo, - final Object value) throws BufferUnderflowException { - switch (fieldInfo.annotation.type()) { - case U8: - output.put((byte) (((short) value) & 0xFF)); - break; - case U16: - output.putShort((short) (((int) value) & 0xFFFF)); - break; - case U32: - output.putInt((int) (((long) value) & 0xFFFFFFFFL)); - break; - case U63: - output.putLong((long) value); - break; - case U64: - output.put(bigIntegerToU64Bytes((BigInteger) value, output.order(), Type.U64)); - break; - case S8: - output.put((byte) value); - break; - case S16: - output.putShort((short) value); - break; - case S32: - output.putInt((int) value); - break; - case S64: - output.putLong((long) value); - break; - case UBE16: - if (output.order() == ByteOrder.LITTLE_ENDIAN) { - output.putShort(Short.reverseBytes((short) (((int) value) & 0xFFFF))); - } else { - output.putShort((short) (((int) value) & 0xFFFF)); - } - break; - case UBE32: - if (output.order() == ByteOrder.LITTLE_ENDIAN) { - output.putInt(Integer.reverseBytes( - (int) (((long) value) & 0xFFFFFFFFL))); - } else { - output.putInt((int) (((long) value) & 0xFFFFFFFFL)); - } - break; - case UBE63: - if (output.order() == ByteOrder.LITTLE_ENDIAN) { - output.putLong(Long.reverseBytes((long) value)); - } else { - output.putLong((long) value); - } - break; - case UBE64: - output.put(bigIntegerToU64Bytes((BigInteger) value, output.order(), Type.UBE64)); - break; - case ByteArray: - checkByteArraySize((byte[]) value, fieldInfo); - output.put((byte[]) value); - break; - case EUI48: - final byte[] macAddress = ((MacAddress) value).toByteArray(); - output.put(macAddress); - break; - case Ipv4Address: - case Ipv6Address: - final byte[] address = ((InetAddress) value).getAddress(); - output.put(address); - break; - default: - throw new IllegalArgumentException("Unknown type:" + fieldInfo.annotation.type()); - } - - // padding zero after field value for alignment. - for (int i = 0; i < fieldInfo.annotation.padding(); i++) output.put((byte) 0); - } - - private static FieldInfo[] getClassFieldInfo(final Class clazz) { - if (!isStructSubclass(clazz)) { - throw new IllegalArgumentException(clazz.getName() + " is not a subclass of " - + Struct.class.getName() + ", its superclass is " - + clazz.getSuperclass().getName()); - } - - final FieldInfo[] cachedAnnotationFields = sFieldCache.get(clazz); - if (cachedAnnotationFields != null) { - return cachedAnnotationFields; - } - - // Since array returned from Class#getDeclaredFields doesn't guarantee the actual order - // of field appeared in the class, that is a problem when parsing raw data read from - // ByteBuffer. Store the fields appeared by the order() defined in the Field annotation. - final FieldInfo[] annotationFields = new FieldInfo[getAnnotationFieldCount(clazz)]; - for (java.lang.reflect.Field field : clazz.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers())) continue; - - final Field annotation = field.getAnnotation(Field.class); - if (annotation == null) { - throw new IllegalArgumentException("Field " + field.getName() - + " is missing the " + Field.class.getSimpleName() - + " annotation"); - } - if (annotation.order() < 0 || annotation.order() >= annotationFields.length) { - throw new IllegalArgumentException("Annotation order: " + annotation.order() - + " is negative or non-consecutive"); - } - if (annotationFields[annotation.order()] != null) { - throw new IllegalArgumentException("Duplicated annotation order: " - + annotation.order()); - } - annotationFields[annotation.order()] = new FieldInfo(annotation, field); - } - sFieldCache.putIfAbsent(clazz, annotationFields); - return annotationFields; - } - - /** - * Parse raw data from ByteBuffer according to the pre-defined annotation rule and return - * the type-variable object which is subclass of Struct class. - * - * TODO: - * 1. Support subclass inheritance. - * 2. Introduce annotation processor to enforce the subclass naming schema. - */ - public static <T> T parse(final Class<T> clazz, final ByteBuffer buf) { - try { - final FieldInfo[] foundFields = getClassFieldInfo(clazz); - if (hasBothMutableAndImmutableFields(foundFields)) { - throw new IllegalArgumentException("Class has both final and non-final fields"); - } - - Constructor<?> constructor = null; - Constructor<?> defaultConstructor = null; - final Constructor<?>[] constructors = clazz.getDeclaredConstructors(); - for (Constructor cons : constructors) { - if (matchConstructor(cons, foundFields)) constructor = cons; - if (cons.getParameterTypes().length == 0) defaultConstructor = cons; - } - - if (constructor == null && defaultConstructor == null) { - throw new IllegalArgumentException("Fail to find available constructor"); - } - if (constructor != null) { - final Object[] args = new Object[foundFields.length]; - for (int i = 0; i < args.length; i++) { - args[i] = getFieldValue(buf, foundFields[i]); - } - return (T) constructor.newInstance(args); - } - - final Object instance = defaultConstructor.newInstance(); - for (FieldInfo fi : foundFields) { - fi.field.set(instance, getFieldValue(buf, fi)); - } - return (T) instance; - } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - throw new IllegalArgumentException("Fail to create a instance from constructor", e); - } catch (BufferUnderflowException e) { - throw new IllegalArgumentException("Fail to read raw data from ByteBuffer", e); - } - } - - private static int getSizeInternal(final FieldInfo[] fieldInfos) { - int size = 0; - for (FieldInfo fi : fieldInfos) { - size += getFieldLength(fi.annotation); - } - return size; - } - - // Check whether the actual size of byte array matches the array size declared in - // annotation. For other annotation types, the actual length of field could be always - // deduced from annotation correctly. - private static void checkByteArraySize(@Nullable final byte[] array, - @NonNull final FieldInfo fieldInfo) { - Objects.requireNonNull(array, "null byte array for field " + fieldInfo.field.getName()); - int annotationArraySize = fieldInfo.annotation.arraysize(); - if (array.length == annotationArraySize) return; - throw new IllegalStateException("byte array actual length: " - + array.length + " doesn't match the declared array size: " + annotationArraySize); - } - - private void writeToByteBufferInternal(final ByteBuffer output, final FieldInfo[] fieldInfos) { - for (FieldInfo fi : fieldInfos) { - final Object value = getFieldValue(fi.field); - try { - putFieldValue(output, fi, value); - } catch (BufferUnderflowException e) { - throw new IllegalArgumentException("Fail to fill raw data to ByteBuffer", e); - } - } - } - - /** - * Get the size of Struct subclass object. - */ - public static <T extends Struct> int getSize(final Class<T> clazz) { - final FieldInfo[] fieldInfos = getClassFieldInfo(clazz); - return getSizeInternal(fieldInfos); - } - - /** - * Convert the parsed Struct subclass object to ByteBuffer. - * - * @param output ByteBuffer passed-in from the caller. - */ - public final void writeToByteBuffer(final ByteBuffer output) { - final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); - writeToByteBufferInternal(output, fieldInfos); - } - - /** - * Convert the parsed Struct subclass object to byte array. - * - * @param order indicate ByteBuffer is outputted as little-endian or big-endian. - */ - public final byte[] writeToBytes(final ByteOrder order) { - final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); - final byte[] output = new byte[getSizeInternal(fieldInfos)]; - final ByteBuffer buffer = ByteBuffer.wrap(output); - buffer.order(order); - writeToByteBufferInternal(buffer, fieldInfos); - return output; - } - - /** Convert the parsed Struct subclass object to byte array with native order. */ - public final byte[] writeToBytes() { - return writeToBytes(ByteOrder.nativeOrder()); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || this.getClass() != obj.getClass()) return false; - - final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); - for (int i = 0; i < fieldInfos.length; i++) { - try { - final Object value = fieldInfos[i].field.get(this); - final Object otherValue = fieldInfos[i].field.get(obj); - - // Use Objects#deepEquals because the equals method on arrays does not check the - // contents of the array. The only difference between Objects#deepEquals and - // Objects#equals is that the former will call Arrays#deepEquals when comparing - // arrays. In turn, the only difference between Arrays#deepEquals is that it - // supports nested arrays. Struct does not currently support these, and if it did, - // Objects#deepEquals might be more correct. - if (!Objects.deepEquals(value, otherValue)) return false; - } catch (IllegalAccessException e) { - throw new IllegalStateException("Cannot access field: " + fieldInfos[i].field, e); - } - } - return true; - } - - @Override - public int hashCode() { - final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); - final Object[] values = new Object[fieldInfos.length]; - for (int i = 0; i < fieldInfos.length; i++) { - final Object value = getFieldValue(fieldInfos[i].field); - // For byte array field, put the hash code generated based on the array content into - // the Object array instead of the reference to byte array, which might change and cause - // to get a different hash code even with the exact same elements. - if (fieldInfos[i].field.getType() == byte[].class) { - values[i] = Arrays.hashCode((byte[]) value); - } else { - values[i] = value; - } - } - return Objects.hash(values); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass()); - for (int i = 0; i < fieldInfos.length; i++) { - sb.append(fieldInfos[i].field.getName()).append(": "); - final Object value = getFieldValue(fieldInfos[i].field); - if (value == null) { - sb.append("null"); - } else if (fieldInfos[i].annotation.type() == Type.ByteArray) { - sb.append("0x").append(HexDump.toHexString((byte[]) value)); - } else if (fieldInfos[i].annotation.type() == Type.Ipv4Address - || fieldInfos[i].annotation.type() == Type.Ipv6Address) { - sb.append(((InetAddress) value).getHostAddress()); - } else { - sb.append(value.toString()); - } - if (i != fieldInfos.length - 1) sb.append(", "); - } - return sb.toString(); - } - - /** A simple Struct which only contains a u8 field. */ - public static class U8 extends Struct { - @Struct.Field(order = 0, type = Struct.Type.U8) - public final short val; - - public U8(final short val) { - this.val = val; - } - } - - /** A simple Struct which only contains an s32 field. */ - public static class S32 extends Struct { - @Struct.Field(order = 0, type = Struct.Type.S32) - public final int val; - - public S32(final int val) { - this.val = val; - } - } - - /** A simple Struct which only contains a u32 field. */ - public static class U32 extends Struct { - @Struct.Field(order = 0, type = Struct.Type.U32) - public final long val; - - public U32(final long val) { - this.val = val; - } - } - - /** A simple Struct which only contains an s64 field. */ - public static class S64 extends Struct { - @Struct.Field(order = 0, type = Struct.Type.S64) - public final long val; - - public S64(final long val) { - this.val = val; - } - } -} diff --git a/common/device/com/android/net/module/util/TcUtils.java b/common/device/com/android/net/module/util/TcUtils.java deleted file mode 100644 index 9d2fb7f9..00000000 --- a/common/device/com/android/net/module/util/TcUtils.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util; - -import java.io.IOException; - -/** - * Contains mostly tc-related functionality. - */ -public class TcUtils { - static { - System.loadLibrary(JniUtil.getJniLibraryName(TcUtils.class.getPackage())); - } - - /** - * Checks if the network interface uses an ethernet L2 header. - * - * @param iface the network interface. - * @return true if the interface uses an ethernet L2 header. - * @throws IOException - */ - public static native boolean isEthernet(String iface) throws IOException; - - /** - * Attach a tc bpf filter. - * - * Equivalent to the following 'tc' command: - * tc filter add dev .. in/egress prio .. protocol ipv6/ip bpf object-pinned - * /sys/fs/bpf/... direct-action - * - * @param ifIndex the network interface index. - * @param ingress ingress or egress qdisc. - * @param prio - * @param proto - * @param bpfProgPath - * @throws IOException - */ - public static native void tcFilterAddDevBpf(int ifIndex, boolean ingress, short prio, - short proto, String bpfProgPath) throws IOException; - - /** - * Attach a tc police action. - * - * Attaches a matchall filter to the clsact qdisc with a tc police and tc bpf action attached. - * This causes the ingress rate to be limited and exceeding packets to be forwarded to a bpf - * program (specified in bpfProgPah) that accounts for the packets before dropping them. - * - * Equivalent to the following 'tc' command: - * tc filter add dev .. ingress prio .. protocol .. matchall \ - * action police rate .. burst .. conform-exceed pipe/continue \ - * action bpf object-pinned .. \ - * drop - * - * @param ifIndex the network interface index. - * @param prio the filter preference. - * @param proto protocol. - * @param rateInBytesPerSec rate limit in bytes/s. - * @param bpfProgPath bpg program that accounts for rate exceeding packets before they are - * dropped. - * @throws IOException - */ - public static native void tcFilterAddDevIngressPolice(int ifIndex, short prio, short proto, - int rateInBytesPerSec, String bpfProgPath) throws IOException; - - /** - * Delete a tc filter. - * - * Equivalent to the following 'tc' command: - * tc filter del dev .. in/egress prio .. protocol .. - * - * @param ifIndex the network interface index. - * @param ingress ingress or egress qdisc. - * @param prio the filter preference. - * @param proto protocol. - * @throws IOException - */ - public static native void tcFilterDelDev(int ifIndex, boolean ingress, short prio, - short proto) throws IOException; - - /** - * Add a clsact qdisc. - * - * Equivalent to the following 'tc' command: - * tc qdisc add dev .. clsact - * - * @param ifIndex the network interface index. - * @throws IOException - */ - public static native void tcQdiscAddDevClsact(int ifIndex) throws IOException; -} diff --git a/common/device/com/android/net/module/util/arp/ArpPacket.java b/common/device/com/android/net/module/util/arp/ArpPacket.java deleted file mode 100644 index dab9694b..00000000 --- a/common/device/com/android/net/module/util/arp/ArpPacket.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.arp; - -import static android.system.OsConstants.ETH_P_ARP; -import static android.system.OsConstants.ETH_P_IP; - -import static com.android.net.module.util.NetworkStackConstants.ARP_ETHER_IPV4_LEN; -import static com.android.net.module.util.NetworkStackConstants.ARP_HWTYPE_ETHER; -import static com.android.net.module.util.NetworkStackConstants.ARP_REPLY; -import static com.android.net.module.util.NetworkStackConstants.ARP_REQUEST; -import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; - -import android.net.MacAddress; - -import com.android.internal.annotations.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; - -/** - * Defines basic data and operations needed to build and parse packets for the - * ARP protocol. - * - * @hide - */ -public class ArpPacket { - private static final String TAG = "ArpPacket"; - - public final short opCode; - public final Inet4Address senderIp; - public final Inet4Address targetIp; - public final MacAddress senderHwAddress; - public final MacAddress targetHwAddress; - - ArpPacket(short opCode, MacAddress senderHwAddress, Inet4Address senderIp, - MacAddress targetHwAddress, Inet4Address targetIp) { - this.opCode = opCode; - this.senderHwAddress = senderHwAddress; - this.senderIp = senderIp; - this.targetHwAddress = targetHwAddress; - this.targetIp = targetIp; - } - - /** - * Build an ARP packet from the required specified parameters. - */ - @VisibleForTesting - public static ByteBuffer buildArpPacket(final byte[] dstMac, final byte[] srcMac, - final byte[] targetIp, final byte[] targetHwAddress, byte[] senderIp, - final short opCode) { - final ByteBuffer buf = ByteBuffer.allocate(ARP_ETHER_IPV4_LEN); - - // Ether header - buf.put(dstMac); - buf.put(srcMac); - buf.putShort((short) ETH_P_ARP); - - // ARP header - buf.putShort((short) ARP_HWTYPE_ETHER); // hrd - buf.putShort((short) ETH_P_IP); // pro - buf.put((byte) ETHER_ADDR_LEN); // hln - buf.put((byte) IPV4_ADDR_LEN); // pln - buf.putShort(opCode); // op - buf.put(srcMac); // sha - buf.put(senderIp); // spa - buf.put(targetHwAddress); // tha - buf.put(targetIp); // tpa - buf.flip(); - return buf; - } - - /** - * Parse an ARP packet from a ByteBuffer object. - */ - @VisibleForTesting - public static ArpPacket parseArpPacket(final byte[] recvbuf, final int length) - throws ParseException { - try { - if (length < ARP_ETHER_IPV4_LEN || recvbuf.length < length) { - throw new ParseException("Invalid packet length: " + length); - } - - final ByteBuffer buffer = ByteBuffer.wrap(recvbuf, 0, length); - byte[] l2dst = new byte[ETHER_ADDR_LEN]; - byte[] l2src = new byte[ETHER_ADDR_LEN]; - buffer.get(l2dst); - buffer.get(l2src); - - final short etherType = buffer.getShort(); - if (etherType != ETH_P_ARP) { - throw new ParseException("Incorrect Ether Type: " + etherType); - } - - final short hwType = buffer.getShort(); - if (hwType != ARP_HWTYPE_ETHER) { - throw new ParseException("Incorrect HW Type: " + hwType); - } - - final short protoType = buffer.getShort(); - if (protoType != ETH_P_IP) { - throw new ParseException("Incorrect Protocol Type: " + protoType); - } - - final byte hwAddrLength = buffer.get(); - if (hwAddrLength != ETHER_ADDR_LEN) { - throw new ParseException("Incorrect HW address length: " + hwAddrLength); - } - - final byte ipAddrLength = buffer.get(); - if (ipAddrLength != IPV4_ADDR_LEN) { - throw new ParseException("Incorrect Protocol address length: " + ipAddrLength); - } - - final short opCode = buffer.getShort(); - if (opCode != ARP_REQUEST && opCode != ARP_REPLY) { - throw new ParseException("Incorrect opCode: " + opCode); - } - - byte[] senderHwAddress = new byte[ETHER_ADDR_LEN]; - byte[] senderIp = new byte[IPV4_ADDR_LEN]; - buffer.get(senderHwAddress); - buffer.get(senderIp); - - byte[] targetHwAddress = new byte[ETHER_ADDR_LEN]; - byte[] targetIp = new byte[IPV4_ADDR_LEN]; - buffer.get(targetHwAddress); - buffer.get(targetIp); - - return new ArpPacket(opCode, MacAddress.fromBytes(senderHwAddress), - (Inet4Address) InetAddress.getByAddress(senderIp), - MacAddress.fromBytes(targetHwAddress), - (Inet4Address) InetAddress.getByAddress(targetIp)); - } catch (IndexOutOfBoundsException e) { - throw new ParseException("Invalid index when wrapping a byte array into a buffer"); - } catch (BufferUnderflowException e) { - throw new ParseException("Invalid buffer position"); - } catch (IllegalArgumentException e) { - throw new ParseException("Invalid MAC address representation"); - } catch (UnknownHostException e) { - throw new ParseException("Invalid IP address of Host"); - } - } - - /** - * Thrown when parsing ARP packet failed. - */ - public static class ParseException extends Exception { - ParseException(String message) { - super(message); - } - } -} diff --git a/common/device/com/android/net/module/util/async/Assertions.java b/common/device/com/android/net/module/util/async/Assertions.java deleted file mode 100644 index ce701d05..00000000 --- a/common/device/com/android/net/module/util/async/Assertions.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -import android.os.Build; - -/** - * Implements basic assert functions for runtime error-checking. - * - * @hide - */ -public final class Assertions { - public static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); - - public static void throwsIfOutOfBounds(int totalLength, int pos, int len) { - if (!IS_USER_BUILD && ((totalLength | pos | len) < 0 || pos > totalLength - len)) { - throw new ArrayIndexOutOfBoundsException( - "length=" + totalLength + "; regionStart=" + pos + "; regionLength=" + len); - } - } - - public static void throwsIfOutOfBounds(byte[] buffer, int pos, int len) { - throwsIfOutOfBounds(buffer != null ? buffer.length : 0, pos, len); - } - - private Assertions() {} -} diff --git a/common/device/com/android/net/module/util/async/AsyncFile.java b/common/device/com/android/net/module/util/async/AsyncFile.java deleted file mode 100644 index 2a3231b7..00000000 --- a/common/device/com/android/net/module/util/async/AsyncFile.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -import java.io.IOException; - -/** - * Represents an EventManager-managed file with Async IO semantics. - * - * Implements level-based Asyn IO semantics. This means that: - * - onReadReady() callback would keep happening as long as there's any remaining - * data to read, or the user calls enableReadEvents(false) - * - onWriteReady() callback would keep happening as long as there's remaining space - * to write to, or the user calls enableWriteEvents(false) - * - * All operations except close() must be called on the EventManager thread. - * - * @hide - */ -public interface AsyncFile { - /** - * Receives notifications when file readability or writeability changes. - * @hide - */ - public interface Listener { - /** Invoked after the underlying file has been closed. */ - void onClosed(AsyncFile file); - - /** Invoked while the file has readable data and read notifications are enabled. */ - void onReadReady(AsyncFile file); - - /** Invoked while the file has writeable space and write notifications are enabled. */ - void onWriteReady(AsyncFile file); - } - - /** Requests this file to be closed. */ - void close(); - - /** Enables or disables onReadReady() events. */ - void enableReadEvents(boolean enable); - - /** Enables or disables onWriteReady() events. */ - void enableWriteEvents(boolean enable); - - /** Returns true if the input stream has reached its end, or has been closed. */ - boolean reachedEndOfFile(); - - /** - * Reads available data from the given non-blocking file descriptor. - * - * Returns zero if there's no data to read at this moment. - * Returns -1 if the file has reached its end or the input stream has been closed. - * Otherwise returns the number of bytes read. - */ - int read(byte[] buffer, int pos, int len) throws IOException; - - /** - * Writes data into the given non-blocking file descriptor. - * - * Returns zero if there's no buffer space to write to at this moment. - * Otherwise returns the number of bytes written. - */ - int write(byte[] buffer, int pos, int len) throws IOException; -} diff --git a/common/device/com/android/net/module/util/async/BufferedFile.java b/common/device/com/android/net/module/util/async/BufferedFile.java deleted file mode 100644 index bb5736b0..00000000 --- a/common/device/com/android/net/module/util/async/BufferedFile.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.async; - -import java.io.IOException; -import java.util.concurrent.atomic.AtomicLong; - -/** - * Buffers inbound and outbound file data within given strict limits. - * - * Automatically manages all readability and writeability events in EventManager: - * - When read buffer has more space - asks EventManager to notify on more data - * - When write buffer has more space - asks the user to provide more data - * - When underlying file cannot accept more data - registers EventManager callback - * - * @hide - */ -public final class BufferedFile implements AsyncFile.Listener { - /** - * Receives notifications when new data or output space is available. - * @hide - */ - public interface Listener { - /** Invoked after the underlying file has been closed. */ - void onBufferedFileClosed(); - - /** Invoked when there's new data in the inbound buffer. */ - void onBufferedFileInboundData(int readByteCount); - - /** Notifies on data being flushed from output buffer. */ - void onBufferedFileOutboundSpace(); - - /** Notifies on unrecoverable error in file access. */ - void onBufferedFileIoError(String message); - } - - private final Listener mListener; - private final EventManager mEventManager; - private AsyncFile mFile; - - private final CircularByteBuffer mInboundBuffer; - private final AtomicLong mTotalBytesRead = new AtomicLong(); - private boolean mIsReadingShutdown; - - private final CircularByteBuffer mOutboundBuffer; - private final AtomicLong mTotalBytesWritten = new AtomicLong(); - - /** Creates BufferedFile based on the given file descriptor. */ - public static BufferedFile create( - EventManager eventManager, - FileHandle fileHandle, - Listener listener, - int inboundBufferSize, - int outboundBufferSize) throws IOException { - if (fileHandle == null) { - throw new NullPointerException(); - } - BufferedFile file = new BufferedFile( - eventManager, listener, inboundBufferSize, outboundBufferSize); - file.mFile = eventManager.registerFile(fileHandle, file); - return file; - } - - private BufferedFile( - EventManager eventManager, - Listener listener, - int inboundBufferSize, - int outboundBufferSize) { - if (eventManager == null || listener == null) { - throw new NullPointerException(); - } - mEventManager = eventManager; - mListener = listener; - - mInboundBuffer = new CircularByteBuffer(inboundBufferSize); - mOutboundBuffer = new CircularByteBuffer(outboundBufferSize); - } - - /** Requests this file to be closed. */ - public void close() { - mFile.close(); - } - - @Override - public void onClosed(AsyncFile file) { - mListener.onBufferedFileClosed(); - } - - /////////////////////////////////////////////////////////////////////////// - // READ PATH - /////////////////////////////////////////////////////////////////////////// - - /** Returns buffer that is automatically filled with inbound data. */ - public ReadableByteBuffer getInboundBuffer() { - return mInboundBuffer; - } - - public int getInboundBufferFreeSizeForTest() { - return mInboundBuffer.freeSize(); - } - - /** Permanently disables reading of this file, and clears all buffered data. */ - public void shutdownReading() { - mIsReadingShutdown = true; - mInboundBuffer.clear(); - mFile.enableReadEvents(false); - } - - /** Returns true after shutdownReading() has been called. */ - public boolean isReadingShutdown() { - return mIsReadingShutdown; - } - - /** Starts or resumes async read operations on this file. */ - public void continueReading() { - if (!mIsReadingShutdown && mInboundBuffer.freeSize() > 0) { - mFile.enableReadEvents(true); - } - } - - @Override - public void onReadReady(AsyncFile file) { - if (mIsReadingShutdown) { - return; - } - - int readByteCount; - try { - readByteCount = bufferInputData(); - } catch (IOException e) { - mListener.onBufferedFileIoError("IOException while reading: " + e.toString()); - return; - } - - if (readByteCount > 0) { - mListener.onBufferedFileInboundData(readByteCount); - } - - continueReading(); - } - - private int bufferInputData() throws IOException { - int totalReadCount = 0; - while (true) { - final int maxReadCount = mInboundBuffer.getDirectWriteSize(); - if (maxReadCount == 0) { - mFile.enableReadEvents(false); - break; - } - - final int bufferOffset = mInboundBuffer.getDirectWritePos(); - final byte[] buffer = mInboundBuffer.getDirectWriteBuffer(); - - final int readCount = mFile.read(buffer, bufferOffset, maxReadCount); - if (readCount <= 0) { - break; - } - - mInboundBuffer.accountForDirectWrite(readCount); - totalReadCount += readCount; - } - - mTotalBytesRead.addAndGet(totalReadCount); - return totalReadCount; - } - - /////////////////////////////////////////////////////////////////////////// - // WRITE PATH - /////////////////////////////////////////////////////////////////////////// - - /** Returns the number of bytes currently buffered for output. */ - public int getOutboundBufferSize() { - return mOutboundBuffer.size(); - } - - /** Returns the number of bytes currently available for buffering for output. */ - public int getOutboundBufferFreeSize() { - return mOutboundBuffer.freeSize(); - } - - /** - * Queues the given data for output. - * Throws runtime exception if there is not enough space. - */ - public boolean enqueueOutboundData(byte[] data, int pos, int len) { - return enqueueOutboundData(data, pos, len, null, 0, 0); - } - - /** - * Queues data1, then data2 for output. - * Throws runtime exception if there is not enough space. - */ - public boolean enqueueOutboundData( - byte[] data1, int pos1, int len1, - byte[] buffer2, int pos2, int len2) { - Assertions.throwsIfOutOfBounds(data1, pos1, len1); - Assertions.throwsIfOutOfBounds(buffer2, pos2, len2); - - final int totalLen = len1 + len2; - - if (totalLen > mOutboundBuffer.freeSize()) { - flushOutboundBuffer(); - - if (totalLen > mOutboundBuffer.freeSize()) { - return false; - } - } - - mOutboundBuffer.writeBytes(data1, pos1, len1); - - if (buffer2 != null) { - mOutboundBuffer.writeBytes(buffer2, pos2, len2); - } - - flushOutboundBuffer(); - - return true; - } - - private void flushOutboundBuffer() { - try { - while (mOutboundBuffer.getDirectReadSize() > 0) { - final int maxReadSize = mOutboundBuffer.getDirectReadSize(); - final int writeCount = mFile.write( - mOutboundBuffer.getDirectReadBuffer(), - mOutboundBuffer.getDirectReadPos(), - maxReadSize); - - if (writeCount == 0) { - mFile.enableWriteEvents(true); - break; - } - - if (writeCount > maxReadSize) { - throw new IllegalArgumentException( - "Write count " + writeCount + " above max " + maxReadSize); - } - - mOutboundBuffer.accountForDirectRead(writeCount); - } - } catch (IOException e) { - scheduleOnIoError("IOException while writing: " + e.toString()); - } - } - - private void scheduleOnIoError(String message) { - mEventManager.execute(() -> { - mListener.onBufferedFileIoError(message); - }); - } - - @Override - public void onWriteReady(AsyncFile file) { - mFile.enableWriteEvents(false); - flushOutboundBuffer(); - mListener.onBufferedFileOutboundSpace(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("file={"); - sb.append(mFile); - sb.append("}"); - if (mIsReadingShutdown) { - sb.append(", readingShutdown"); - } - sb.append("}, inboundBuffer={"); - sb.append(mInboundBuffer); - sb.append("}, outboundBuffer={"); - sb.append(mOutboundBuffer); - sb.append("}, totalBytesRead="); - sb.append(mTotalBytesRead); - sb.append(", totalBytesWritten="); - sb.append(mTotalBytesWritten); - return sb.toString(); - } -} diff --git a/common/device/com/android/net/module/util/async/CircularByteBuffer.java b/common/device/com/android/net/module/util/async/CircularByteBuffer.java deleted file mode 100644 index 92daa08f..00000000 --- a/common/device/com/android/net/module/util/async/CircularByteBuffer.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -import java.util.Arrays; - -/** - * Implements a circular read-write byte buffer. - * - * @hide - */ -public final class CircularByteBuffer implements ReadableByteBuffer { - private final byte[] mBuffer; - private final int mCapacity; - private int mReadPos; - private int mWritePos; - private int mSize; - - public CircularByteBuffer(int capacity) { - mCapacity = capacity; - mBuffer = new byte[mCapacity]; - } - - @Override - public void clear() { - mReadPos = 0; - mWritePos = 0; - mSize = 0; - Arrays.fill(mBuffer, (byte) 0); - } - - @Override - public int capacity() { - return mCapacity; - } - - @Override - public int size() { - return mSize; - } - - /** Returns the amount of remaining writeable space in this buffer. */ - public int freeSize() { - return mCapacity - mSize; - } - - @Override - public byte peek(int offset) { - if (offset < 0 || offset >= size()) { - throw new IllegalArgumentException("Invalid offset=" + offset + ", size=" + size()); - } - - return mBuffer[(mReadPos + offset) % mCapacity]; - } - - @Override - public void readBytes(byte[] dst, int dstPos, int dstLen) { - if (dst != null) { - Assertions.throwsIfOutOfBounds(dst, dstPos, dstLen); - } - if (dstLen > size()) { - throw new IllegalArgumentException("Invalid len=" + dstLen + ", size=" + size()); - } - - while (dstLen > 0) { - final int copyLen = getCopyLen(mReadPos, mWritePos, dstLen); - if (dst != null) { - System.arraycopy(mBuffer, mReadPos, dst, dstPos, copyLen); - } - dstPos += copyLen; - dstLen -= copyLen; - mSize -= copyLen; - mReadPos = (mReadPos + copyLen) % mCapacity; - } - - if (mSize == 0) { - // Reset to the beginning for better contiguous access. - mReadPos = 0; - mWritePos = 0; - } - } - - @Override - public void peekBytes(int offset, byte[] dst, int dstPos, int dstLen) { - Assertions.throwsIfOutOfBounds(dst, dstPos, dstLen); - if (offset + dstLen > size()) { - throw new IllegalArgumentException("Invalid len=" + dstLen - + ", offset=" + offset + ", size=" + size()); - } - - int tmpReadPos = (mReadPos + offset) % mCapacity; - while (dstLen > 0) { - final int copyLen = getCopyLen(tmpReadPos, mWritePos, dstLen); - System.arraycopy(mBuffer, tmpReadPos, dst, dstPos, copyLen); - dstPos += copyLen; - dstLen -= copyLen; - tmpReadPos = (tmpReadPos + copyLen) % mCapacity; - } - } - - @Override - public int getDirectReadSize() { - if (size() == 0) { - return 0; - } - return (mReadPos < mWritePos ? (mWritePos - mReadPos) : (mCapacity - mReadPos)); - } - - @Override - public int getDirectReadPos() { - return mReadPos; - } - - @Override - public byte[] getDirectReadBuffer() { - return mBuffer; - } - - @Override - public void accountForDirectRead(int len) { - if (len < 0 || len > size()) { - throw new IllegalArgumentException("Invalid len=" + len + ", size=" + size()); - } - - mSize -= len; - mReadPos = (mReadPos + len) % mCapacity; - } - - /** Copies given data to the end of the buffer. */ - public void writeBytes(byte[] buffer, int pos, int len) { - Assertions.throwsIfOutOfBounds(buffer, pos, len); - if (len > freeSize()) { - throw new IllegalArgumentException("Invalid len=" + len + ", size=" + freeSize()); - } - - while (len > 0) { - final int copyLen = getCopyLen(mWritePos, mReadPos,len); - System.arraycopy(buffer, pos, mBuffer, mWritePos, copyLen); - pos += copyLen; - len -= copyLen; - mSize += copyLen; - mWritePos = (mWritePos + copyLen) % mCapacity; - } - } - - private int getCopyLen(int startPos, int endPos, int len) { - if (startPos < endPos) { - return Math.min(len, endPos - startPos); - } else { - return Math.min(len, mCapacity - startPos); - } - } - - /** Returns the amount of contiguous writeable space. */ - public int getDirectWriteSize() { - if (freeSize() == 0) { - return 0; // Return zero in case buffer is full. - } - return (mWritePos < mReadPos ? (mReadPos - mWritePos) : (mCapacity - mWritePos)); - } - - /** Returns the position of contiguous writeable space. */ - public int getDirectWritePos() { - return mWritePos; - } - - /** Returns the buffer reference for direct write operation. */ - public byte[] getDirectWriteBuffer() { - return mBuffer; - } - - /** Must be called after performing a direct write using getDirectWriteBuffer(). */ - public void accountForDirectWrite(int len) { - if (len < 0 || len > freeSize()) { - throw new IllegalArgumentException("Invalid len=" + len + ", size=" + freeSize()); - } - - mSize += len; - mWritePos = (mWritePos + len) % mCapacity; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("CircularByteBuffer{c="); - sb.append(mCapacity); - sb.append(",s="); - sb.append(mSize); - sb.append(",r="); - sb.append(mReadPos); - sb.append(",w="); - sb.append(mWritePos); - sb.append('}'); - return sb.toString(); - } -} diff --git a/common/device/com/android/net/module/util/async/EventManager.java b/common/device/com/android/net/module/util/async/EventManager.java deleted file mode 100644 index 4ed4a704..00000000 --- a/common/device/com/android/net/module/util/async/EventManager.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -import java.io.IOException; -import java.util.concurrent.Executor; - -/** - * Manages Async IO files and scheduled alarms, and executes all related callbacks - * in its own thread. - * - * All callbacks of AsyncFile, Alarm and EventManager will execute on EventManager's thread. - * - * Methods of this interface can be called from any thread. - * - * @hide - */ -public interface EventManager extends Executor { - /** - * Represents a scheduled alarm, allowing caller to attempt to cancel that alarm - * before it executes. - * - * @hide - */ - public interface Alarm { - /** @hide */ - public interface Listener { - void onAlarm(Alarm alarm, long elapsedTimeMs); - void onAlarmCancelled(Alarm alarm); - } - - /** - * Attempts to cancel this alarm. Note that this request is inherently - * racy if executed close to the alarm's expiration time. - */ - void cancel(); - } - - /** - * Requests EventManager to manage the given file. - * - * The file descriptors are not cloned, and EventManager takes ownership of all files passed. - * - * No event callbacks are enabled by this method. - */ - AsyncFile registerFile(FileHandle fileHandle, AsyncFile.Listener listener) throws IOException; - - /** - * Schedules Alarm with the given timeout. - * - * Timeout of zero can be used for immediate execution. - */ - Alarm scheduleAlarm(long timeout, Alarm.Listener callback); - - /** Schedules Runnable for immediate execution. */ - @Override - void execute(Runnable callback); - - /** Throws a runtime exception if the caller is not executing on this EventManager's thread. */ - void assertInThread(); -} diff --git a/common/device/com/android/net/module/util/async/FileHandle.java b/common/device/com/android/net/module/util/async/FileHandle.java deleted file mode 100644 index 9f7942d4..00000000 --- a/common/device/com/android/net/module/util/async/FileHandle.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -import android.os.ParcelFileDescriptor; - -import java.io.Closeable; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Represents an file descriptor or another way to access a file. - * - * @hide - */ -public final class FileHandle { - private final ParcelFileDescriptor mFd; - private final Closeable mCloseable; - private final InputStream mInputStream; - private final OutputStream mOutputStream; - - public static FileHandle fromFileDescriptor(ParcelFileDescriptor fd) { - if (fd == null) { - throw new NullPointerException(); - } - return new FileHandle(fd, null, null, null); - } - - public static FileHandle fromBlockingStream( - Closeable closeable, InputStream is, OutputStream os) { - if (closeable == null || is == null || os == null) { - throw new NullPointerException(); - } - return new FileHandle(null, closeable, is, os); - } - - private FileHandle(ParcelFileDescriptor fd, Closeable closeable, - InputStream is, OutputStream os) { - mFd = fd; - mCloseable = closeable; - mInputStream = is; - mOutputStream = os; - } - - ParcelFileDescriptor getFileDescriptor() { - return mFd; - } - - Closeable getCloseable() { - return mCloseable; - } - - InputStream getInputStream() { - return mInputStream; - } - - OutputStream getOutputStream() { - return mOutputStream; - } -} diff --git a/common/device/com/android/net/module/util/async/OsAccess.java b/common/device/com/android/net/module/util/async/OsAccess.java deleted file mode 100644 index df0ded21..00000000 --- a/common/device/com/android/net/module/util/async/OsAccess.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.async; - -import android.os.ParcelFileDescriptor; -import android.system.StructPollfd; - -import java.io.FileDescriptor; -import java.io.IOException; - -/** - * Provides access to all relevant OS functions.. - * - * @hide - */ -public abstract class OsAccess { - /** Closes the given file, suppressing IO exceptions. */ - public abstract void close(ParcelFileDescriptor fd); - - /** Returns file name for debugging purposes. */ - public abstract String getFileDebugName(ParcelFileDescriptor fd); - - /** Returns inner FileDescriptor instance. */ - public abstract FileDescriptor getInnerFileDescriptor(ParcelFileDescriptor fd); - - /** - * Reads available data from the given non-blocking file descriptor. - * - * Returns zero if there's no data to read at this moment. - * Returns -1 if the file has reached its end or the input stream has been closed. - * Otherwise returns the number of bytes read. - */ - public abstract int read(FileDescriptor fd, byte[] buffer, int pos, int len) - throws IOException; - - /** - * Writes data into the given non-blocking file descriptor. - * - * Returns zero if there's no buffer space to write to at this moment. - * Otherwise returns the number of bytes written. - */ - public abstract int write(FileDescriptor fd, byte[] buffer, int pos, int len) - throws IOException; - - public abstract long monotonicTimeMillis(); - public abstract void setNonBlocking(FileDescriptor fd) throws IOException; - public abstract ParcelFileDescriptor[] pipe() throws IOException; - - public abstract int poll(StructPollfd[] fds, int timeoutMs) throws IOException; - public abstract short getPollInMask(); - public abstract short getPollOutMask(); -} diff --git a/common/device/com/android/net/module/util/async/ReadableByteBuffer.java b/common/device/com/android/net/module/util/async/ReadableByteBuffer.java deleted file mode 100644 index 7f824049..00000000 --- a/common/device/com/android/net/module/util/async/ReadableByteBuffer.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.async; - -/** - * Allows reading from a buffer of bytes. The data can be read and thus removed, - * or peeked at without disturbing the buffer state. - * - * @hide - */ -public interface ReadableByteBuffer { - /** Returns the size of the buffered data. */ - int size(); - - /** - * Returns the maximum amount of the buffered data. - * - * The caller may use this method in combination with peekBytes() - * to estimate when the buffer needs to be emptied using readData(). - */ - int capacity(); - - /** Clears all buffered data. */ - void clear(); - - /** Returns a single byte at the given offset. */ - byte peek(int offset); - - /** Copies an array of bytes from the given offset to "dst". */ - void peekBytes(int offset, byte[] dst, int dstPos, int dstLen); - - /** Reads and removes an array of bytes from the head of the buffer. */ - void readBytes(byte[] dst, int dstPos, int dstLen); - - /** Returns the amount of contiguous readable data. */ - int getDirectReadSize(); - - /** Returns the position of contiguous readable data. */ - int getDirectReadPos(); - - /** Returns the buffer reference for direct read operation. */ - byte[] getDirectReadBuffer(); - - /** Must be called after performing a direct read using getDirectReadBuffer(). */ - void accountForDirectRead(int len); -} diff --git a/common/device/com/android/net/module/util/ip/ConntrackMonitor.java b/common/device/com/android/net/module/util/ip/ConntrackMonitor.java deleted file mode 100644 index 420a5446..00000000 --- a/common/device/com/android/net/module/util/ip/ConntrackMonitor.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.ip; - -import static com.android.net.module.util.netlink.ConntrackMessage.DYING_MASK; -import static com.android.net.module.util.netlink.ConntrackMessage.ESTABLISHED_MASK; - -import android.annotation.NonNull; -import android.os.Handler; -import android.system.OsConstants; - -import com.android.internal.annotations.VisibleForTesting; -import com.android.net.module.util.SharedLog; -import com.android.net.module.util.netlink.ConntrackMessage; -import com.android.net.module.util.netlink.NetlinkConstants; -import com.android.net.module.util.netlink.NetlinkMessage; - -import java.util.Objects; - - -/** - * ConntrackMonitor. - * - * Monitors the netfilter conntrack notifications and presents to callers - * ConntrackEvents describing each event. - * - * @hide - */ -public class ConntrackMonitor extends NetlinkMonitor { - private static final String TAG = ConntrackMonitor.class.getSimpleName(); - private static final boolean DBG = false; - private static final boolean VDBG = false; - - // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h - public static final int NF_NETLINK_CONNTRACK_NEW = 1; - public static final int NF_NETLINK_CONNTRACK_UPDATE = 2; - public static final int NF_NETLINK_CONNTRACK_DESTROY = 4; - - // The socket receive buffer size in bytes. If too many conntrack messages are sent too - // quickly, the conntrack messages can overflow the socket receive buffer. This can happen - // if too many connections are disconnected by losing network and so on. Use a large-enough - // buffer to avoid the error ENOBUFS while listening to the conntrack messages. - private static final int SOCKET_RECV_BUFSIZE = 6 * 1024 * 1024; - - /** - * A class for describing parsed netfilter conntrack events. - */ - public static class ConntrackEvent { - /** - * Conntrack event type. - */ - public final short msgType; - /** - * Original direction conntrack tuple. - */ - public final ConntrackMessage.Tuple tupleOrig; - /** - * Reply direction conntrack tuple. - */ - public final ConntrackMessage.Tuple tupleReply; - /** - * Connection status. A bitmask of ip_conntrack_status enum flags. - */ - public final int status; - /** - * Conntrack timeout. - */ - public final int timeoutSec; - - public ConntrackEvent(ConntrackMessage msg) { - this.msgType = msg.getHeader().nlmsg_type; - this.tupleOrig = msg.tupleOrig; - this.tupleReply = msg.tupleReply; - this.status = msg.status; - this.timeoutSec = msg.timeoutSec; - } - - @VisibleForTesting - public ConntrackEvent(short msgType, ConntrackMessage.Tuple tupleOrig, - ConntrackMessage.Tuple tupleReply, int status, int timeoutSec) { - this.msgType = msgType; - this.tupleOrig = tupleOrig; - this.tupleReply = tupleReply; - this.status = status; - this.timeoutSec = timeoutSec; - } - - @Override - @VisibleForTesting - public boolean equals(Object o) { - if (!(o instanceof ConntrackEvent)) return false; - ConntrackEvent that = (ConntrackEvent) o; - return this.msgType == that.msgType - && Objects.equals(this.tupleOrig, that.tupleOrig) - && Objects.equals(this.tupleReply, that.tupleReply) - && this.status == that.status - && this.timeoutSec == that.timeoutSec; - } - - @Override - public int hashCode() { - return Objects.hash(msgType, tupleOrig, tupleReply, status, timeoutSec); - } - - @Override - public String toString() { - return "ConntrackEvent{" - + "msg_type{" - + NetlinkConstants.stringForNlMsgType(msgType, OsConstants.NETLINK_NETFILTER) - + "}, " - + "tuple_orig{" + tupleOrig + "}, " - + "tuple_reply{" + tupleReply + "}, " - + "status{" - + status + "(" + ConntrackMessage.stringForIpConntrackStatus(status) + ")" - + "}, " - + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}" - + "}"; - } - - /** - * Check the established NAT session conntrack message. - * - * @param msg the conntrack message to check. - * @return true if an established NAT message, false if not. - */ - public static boolean isEstablishedNatSession(@NonNull ConntrackMessage msg) { - if (msg.getMessageType() != NetlinkConstants.IPCTNL_MSG_CT_NEW) return false; - if (msg.tupleOrig == null) return false; - if (msg.tupleReply == null) return false; - if (msg.timeoutSec == 0) return false; - if ((msg.status & ESTABLISHED_MASK) != ESTABLISHED_MASK) return false; - - return true; - } - - /** - * Check the dying NAT session conntrack message. - * Note that IPCTNL_MSG_CT_DELETE event has no CTA_TIMEOUT attribute. - * - * @param msg the conntrack message to check. - * @return true if a dying NAT message, false if not. - */ - public static boolean isDyingNatSession(@NonNull ConntrackMessage msg) { - if (msg.getMessageType() != NetlinkConstants.IPCTNL_MSG_CT_DELETE) return false; - if (msg.tupleOrig == null) return false; - if (msg.tupleReply == null) return false; - if (msg.timeoutSec != 0) return false; - if ((msg.status & DYING_MASK) != DYING_MASK) return false; - - return true; - } - } - - /** - * A callback to caller for conntrack event. - */ - public interface ConntrackEventConsumer { - /** - * Every conntrack event received on the netlink socket is passed in - * here. - */ - void accept(@NonNull ConntrackEvent event); - } - - private final ConntrackEventConsumer mConsumer; - - public ConntrackMonitor(@NonNull Handler h, @NonNull SharedLog log, - @NonNull ConntrackEventConsumer cb) { - super(h, log, TAG, OsConstants.NETLINK_NETFILTER, NF_NETLINK_CONNTRACK_NEW - | NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY, SOCKET_RECV_BUFSIZE); - mConsumer = cb; - } - - @Override - public void processNetlinkMessage(NetlinkMessage nlMsg, final long whenMs) { - if (!(nlMsg instanceof ConntrackMessage)) { - mLog.e("non-conntrack msg: " + nlMsg); - return; - } - - final ConntrackMessage conntrackMsg = (ConntrackMessage) nlMsg; - if (!(ConntrackEvent.isEstablishedNatSession(conntrackMsg) - || ConntrackEvent.isDyingNatSession(conntrackMsg))) { - return; - } - - mConsumer.accept(new ConntrackEvent(conntrackMsg)); - } -} diff --git a/common/device/com/android/net/module/util/ip/InterfaceController.java b/common/device/com/android/net/module/util/ip/InterfaceController.java deleted file mode 100644 index 7277fec0..00000000 --- a/common/device/com/android/net/module/util/ip/InterfaceController.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.ip; - -import static android.net.INetd.IF_STATE_DOWN; -import static android.net.INetd.IF_STATE_UP; - -import android.net.INetd; -import android.net.InterfaceConfigurationParcel; -import android.net.LinkAddress; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.OsConstants; - -import com.android.net.module.util.SharedLog; - -import java.net.Inet4Address; -import java.net.InetAddress; - -/** - * Encapsulates the multiple IP configuration operations performed on an interface. - * - * TODO: refactor/eliminate the redundant ways to set and clear addresses. - * - * @hide - */ -public class InterfaceController { - private static final boolean DBG = false; - - private final String mIfName; - private final INetd mNetd; - private final SharedLog mLog; - - public InterfaceController(String ifname, INetd netd, SharedLog log) { - mIfName = ifname; - mNetd = netd; - mLog = log; - } - - /** - * Set the IPv4 address and also optionally bring the interface up or down. - */ - public boolean setInterfaceConfiguration(final LinkAddress ipv4Addr, - final Boolean setIfaceUp) { - if (!(ipv4Addr.getAddress() instanceof Inet4Address)) { - throw new IllegalArgumentException("Invalid or mismatched Inet4Address"); - } - // Note: currently netd only support INetd#IF_STATE_UP and #IF_STATE_DOWN. - // Other flags would be ignored. - - final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); - ifConfig.ifName = mIfName; - ifConfig.ipv4Addr = ipv4Addr.getAddress().getHostAddress(); - ifConfig.prefixLength = ipv4Addr.getPrefixLength(); - // Netd ignores hwaddr in interfaceSetCfg. - ifConfig.hwAddr = ""; - if (setIfaceUp == null) { - // Empty array means no change. - ifConfig.flags = new String[0]; - } else { - // Netd ignores any flag that's not IF_STATE_UP or IF_STATE_DOWN in interfaceSetCfg. - ifConfig.flags = setIfaceUp.booleanValue() - ? new String[] {IF_STATE_UP} : new String[] {IF_STATE_DOWN}; - } - try { - mNetd.interfaceSetCfg(ifConfig); - } catch (RemoteException | ServiceSpecificException e) { - logError("Setting IPv4 address to %s/%d failed: %s", - ifConfig.ipv4Addr, ifConfig.prefixLength, e); - return false; - } - return true; - } - - /** - * Set the IPv4 address of the interface. - */ - public boolean setIPv4Address(final LinkAddress address) { - return setInterfaceConfiguration(address, null); - } - - /** - * Clear the IPv4Address of the interface. - */ - public boolean clearIPv4Address() { - return setIPv4Address(new LinkAddress("0.0.0.0/0")); - } - - private boolean setEnableIPv6(boolean enabled) { - try { - mNetd.interfaceSetEnableIPv6(mIfName, enabled); - } catch (RemoteException | ServiceSpecificException e) { - logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); - return false; - } - return true; - } - - /** - * Enable IPv6 on the interface. - */ - public boolean enableIPv6() { - return setEnableIPv6(true); - } - - /** - * Disable IPv6 on the interface. - */ - public boolean disableIPv6() { - return setEnableIPv6(false); - } - - /** - * Enable or disable IPv6 privacy extensions on the interface. - * @param enabled Whether the extensions should be enabled. - */ - public boolean setIPv6PrivacyExtensions(boolean enabled) { - try { - mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); - } catch (RemoteException | ServiceSpecificException e) { - logError("error %s IPv6 privacy extensions: %s", - (enabled ? "enabling" : "disabling"), e); - return false; - } - return true; - } - - /** - * Set IPv6 address generation mode on the interface. - * - * <p>IPv6 should be disabled before changing the mode. - */ - public boolean setIPv6AddrGenModeIfSupported(int mode) { - try { - mNetd.setIPv6AddrGenMode(mIfName, mode); - } catch (RemoteException e) { - logError("Unable to set IPv6 addrgen mode: %s", e); - return false; - } catch (ServiceSpecificException e) { - if (e.errorCode != OsConstants.EOPNOTSUPP) { - logError("Unable to set IPv6 addrgen mode: %s", e); - return false; - } - } - return true; - } - - /** - * Add an address to the interface. - */ - public boolean addAddress(LinkAddress addr) { - return addAddress(addr.getAddress(), addr.getPrefixLength()); - } - - /** - * Add an address to the interface. - */ - public boolean addAddress(InetAddress ip, int prefixLen) { - try { - mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); - } catch (ServiceSpecificException | RemoteException e) { - logError("failed to add %s/%d: %s", ip, prefixLen, e); - return false; - } - return true; - } - - /** - * Remove an address from the interface. - */ - public boolean removeAddress(InetAddress ip, int prefixLen) { - try { - mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); - } catch (ServiceSpecificException | RemoteException e) { - logError("failed to remove %s/%d: %s", ip, prefixLen, e); - return false; - } - return true; - } - - /** - * Remove all addresses from the interface. - */ - public boolean clearAllAddresses() { - try { - mNetd.interfaceClearAddrs(mIfName); - } catch (Exception e) { - logError("Failed to clear addresses: %s", e); - return false; - } - return true; - } - - private void logError(String fmt, Object... args) { - mLog.e(String.format(fmt, args)); - } -} diff --git a/common/device/com/android/net/module/util/ip/IpNeighborMonitor.java b/common/device/com/android/net/module/util/ip/IpNeighborMonitor.java deleted file mode 100644 index e88e7f0c..00000000 --- a/common/device/com/android/net/module/util/ip/IpNeighborMonitor.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.net.module.util.ip; - -import static android.system.OsConstants.NETLINK_ROUTE; - -import static com.android.net.module.util.netlink.NetlinkConstants.RTM_DELNEIGH; -import static com.android.net.module.util.netlink.NetlinkConstants.hexify; -import static com.android.net.module.util.netlink.NetlinkConstants.stringForNlMsgType; - -import android.annotation.NonNull; -import android.net.MacAddress; -import android.os.Handler; -import android.system.ErrnoException; -import android.system.OsConstants; -import android.util.Log; - -import com.android.net.module.util.SharedLog; -import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.net.module.util.netlink.NetlinkUtils; -import com.android.net.module.util.netlink.RtNetlinkNeighborMessage; -import com.android.net.module.util.netlink.StructNdMsg; - -import java.net.InetAddress; -import java.util.StringJoiner; - -/** - * IpNeighborMonitor. - * - * Monitors the kernel rtnetlink neighbor notifications and presents to callers - * NeighborEvents describing each event. Callers can provide a consumer instance - * to both filter (e.g. by interface index and IP address) and handle the - * generated NeighborEvents. - * - * @hide - */ -public class IpNeighborMonitor extends NetlinkMonitor { - private static final String TAG = IpNeighborMonitor.class.getSimpleName(); - private static final boolean DBG = false; - private static final boolean VDBG = false; - - /** - * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND) - * for the given IP address on the specified interface index. - * - * @return 0 if the request was successfully passed to the kernel; otherwise return - * a non-zero error code. - */ - public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) { - final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex; - if (DBG) Log.d(TAG, msgSnippet); - - final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage( - 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null); - - try { - NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - } catch (ErrnoException e) { - Log.e(TAG, "Error " + msgSnippet + ": " + e); - return -e.errno; - } - - return 0; - } - - /** - * An event about a neighbor. - */ - public static class NeighborEvent { - public final long elapsedMs; - public final short msgType; - public final int ifindex; - @NonNull - public final InetAddress ip; - public final short nudState; - @NonNull - public final MacAddress macAddr; - - public NeighborEvent(long elapsedMs, short msgType, int ifindex, @NonNull InetAddress ip, - short nudState, @NonNull MacAddress macAddr) { - this.elapsedMs = elapsedMs; - this.msgType = msgType; - this.ifindex = ifindex; - this.ip = ip; - this.nudState = nudState; - this.macAddr = macAddr; - } - - boolean isConnected() { - return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateConnected(nudState); - } - - public boolean isValid() { - return (msgType != RTM_DELNEIGH) && StructNdMsg.isNudStateValid(nudState); - } - - @Override - public String toString() { - final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}"); - return j.add("@" + elapsedMs) - .add(stringForNlMsgType(msgType, NETLINK_ROUTE)) - .add("if=" + ifindex) - .add(ip.getHostAddress()) - .add(StructNdMsg.stringForNudState(nudState)) - .add("[" + macAddr + "]") - .toString(); - } - } - - /** - * A client that consumes NeighborEvent instances. - * Implement this to listen to neighbor events. - */ - public interface NeighborEventConsumer { - // Every neighbor event received on the netlink socket is passed in - // here. Subclasses should filter for events of interest. - /** - * Consume a neighbor event - * @param event the event - */ - void accept(NeighborEvent event); - } - - private final NeighborEventConsumer mConsumer; - - public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { - super(h, log, TAG, NETLINK_ROUTE, OsConstants.RTMGRP_NEIGH); - mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; - } - - @Override - public void processNetlinkMessage(NetlinkMessage nlMsg, final long whenMs) { - if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { - mLog.e("non-rtnetlink neighbor msg: " + nlMsg); - return; - } - - final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) nlMsg; - final short msgType = neighMsg.getHeader().nlmsg_type; - final StructNdMsg ndMsg = neighMsg.getNdHeader(); - if (ndMsg == null) { - mLog.e("RtNetlinkNeighborMessage without ND message header!"); - return; - } - - final int ifindex = ndMsg.ndm_ifindex; - final InetAddress destination = neighMsg.getDestination(); - final short nudState = - (msgType == RTM_DELNEIGH) - ? StructNdMsg.NUD_NONE - : ndMsg.ndm_state; - - final NeighborEvent event = new NeighborEvent( - whenMs, msgType, ifindex, destination, nudState, - getMacAddress(neighMsg.getLinkLayerAddress())); - - if (VDBG) { - Log.d(TAG, neighMsg.toString()); - } - if (DBG) { - Log.d(TAG, event.toString()); - } - - mConsumer.accept(event); - } - - private static MacAddress getMacAddress(byte[] linkLayerAddress) { - if (linkLayerAddress != null) { - try { - return MacAddress.fromBytes(linkLayerAddress); - } catch (IllegalArgumentException e) { - Log.e(TAG, "Failed to parse link-layer address: " + hexify(linkLayerAddress)); - } - } - - return null; - } -} diff --git a/common/device/com/android/net/module/util/ip/NetlinkMonitor.java b/common/device/com/android/net/module/util/ip/NetlinkMonitor.java deleted file mode 100644 index f882483d..00000000 --- a/common/device/com/android/net/module/util/ip/NetlinkMonitor.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.ip; - -import static android.system.OsConstants.AF_NETLINK; -import static android.system.OsConstants.ENOBUFS; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOCK_NONBLOCK; -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_RCVBUF; - -import static com.android.net.module.util.SocketUtils.closeSocketQuietly; -import static com.android.net.module.util.SocketUtils.makeNetlinkSocketAddress; -import static com.android.net.module.util.netlink.NetlinkConstants.hexify; - -import android.annotation.NonNull; -import android.os.Handler; -import android.os.SystemClock; -import android.system.ErrnoException; -import android.system.Os; -import android.util.Log; - -import com.android.net.module.util.PacketReader; -import com.android.net.module.util.SharedLog; -import com.android.net.module.util.netlink.NetlinkErrorMessage; -import com.android.net.module.util.netlink.NetlinkMessage; -import com.android.net.module.util.netlink.NetlinkUtils; - -import java.io.FileDescriptor; -import java.net.SocketAddress; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A simple base class to listen for netlink broadcasts. - * - * Opens a netlink socket of the given family and binds to the specified groups. Polls the socket - * from the event loop of the passed-in {@link Handler}, and calls the subclass-defined - * {@link #processNetlinkMessage} method on the handler thread for each netlink message that - * arrives. Currently ignores all netlink errors. - * @hide - */ -public class NetlinkMonitor extends PacketReader { - protected final SharedLog mLog; - protected final String mTag; - private final int mFamily; - private final int mBindGroups; - private final int mSockRcvbufSize; - - private static final boolean DBG = false; - - // Default socket receive buffer size. This means the specific buffer size is not set. - private static final int DEFAULT_SOCKET_RECV_BUFSIZE = -1; - - /** - * Constructs a new {@code NetlinkMonitor} instance. - * - * @param h The Handler on which to poll for messages and on which to call - * {@link #processNetlinkMessage}. - * @param log A SharedLog to log to. - * @param tag The log tag to use for log messages. - * @param family the Netlink socket family to, e.g., {@code NETLINK_ROUTE}. - * @param bindGroups the netlink groups to bind to. - * @param sockRcvbufSize the specific socket receive buffer size in bytes. -1 means that don't - * set the specific socket receive buffer size in #createFd and use the default value in - * /proc/sys/net/core/rmem_default file. See SO_RCVBUF in man-pages/socket. - */ - public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, - int family, int bindGroups, int sockRcvbufSize) { - super(h, NetlinkUtils.DEFAULT_RECV_BUFSIZE); - mLog = log.forSubComponent(tag); - mTag = tag; - mFamily = family; - mBindGroups = bindGroups; - mSockRcvbufSize = sockRcvbufSize; - } - - public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, - int family, int bindGroups) { - this(h, log, tag, family, bindGroups, DEFAULT_SOCKET_RECV_BUFSIZE); - } - - @Override - protected FileDescriptor createFd() { - FileDescriptor fd = null; - - try { - fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, mFamily); - if (mSockRcvbufSize != DEFAULT_SOCKET_RECV_BUFSIZE) { - try { - Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, mSockRcvbufSize); - } catch (ErrnoException e) { - Log.wtf(mTag, "Failed to set SO_RCVBUF to " + mSockRcvbufSize, e); - } - } - Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups)); - NetlinkUtils.connectSocketToNetlink(fd); - - if (DBG) { - final SocketAddress nlAddr = Os.getsockname(fd); - Log.d(mTag, "bound to sockaddr_nl{" + nlAddr.toString() + "}"); - } - } catch (ErrnoException | SocketException e) { - logError("Failed to create rtnetlink socket", e); - closeSocketQuietly(fd); - return null; - } - - return fd; - } - - @Override - protected void handlePacket(byte[] recvbuf, int length) { - final long whenMs = SystemClock.elapsedRealtime(); - final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length); - byteBuffer.order(ByteOrder.nativeOrder()); - - while (byteBuffer.remaining() > 0) { - try { - final int position = byteBuffer.position(); - final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer, mFamily); - if (nlMsg == null || nlMsg.getHeader() == null) { - byteBuffer.position(position); - mLog.e("unparsable netlink msg: " + hexify(byteBuffer)); - break; - } - - if (nlMsg instanceof NetlinkErrorMessage) { - mLog.e("netlink error: " + nlMsg); - continue; - } - - processNetlinkMessage(nlMsg, whenMs); - } catch (Exception e) { - mLog.e("Error handling netlink message", e); - } - } - } - - @Override - protected void logError(String msg, Exception e) { - mLog.e(msg, e); - } - - // Ignoring ENOBUFS may miss any important netlink messages, there are some messages which - // cannot be recovered by dumping current state once missed since kernel doesn't keep state - // for it. In addition, dumping current state will not result in any RTM_DELxxx messages, so - // reconstructing current state from a dump will be difficult. However, for those netlink - // messages don't cause any state changes, e.g. RTM_NEWLINK with current link state, maybe - // it's okay to ignore them, because these netlink messages won't cause any changes on the - // LinkProperties. Given the above trade-offs, try to ignore ENOBUFS and that's similar to - // what netd does today. - // - // TODO: log metrics when ENOBUFS occurs, or even force a disconnect, it will help see how - // often this error occurs on fields with the associated socket receive buffer size. - @Override - protected boolean handleReadError(ErrnoException e) { - logError("readPacket error: ", e); - if (e.errno == ENOBUFS) { - Log.wtf(mTag, "Errno: ENOBUFS"); - return false; - } - return true; - } - - /** - * Processes one netlink message. Must be overridden by subclasses. - * @param nlMsg the message to process. - * @param whenMs the timestamp, as measured by {@link SystemClock#elapsedRealtime}, when the - * message was received. - */ - protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { } -} diff --git a/common/device/com/android/net/module/util/netlink/ConntrackMessage.java b/common/device/com/android/net/module/util/netlink/ConntrackMessage.java deleted file mode 100644 index dfed3efb..00000000 --- a/common/device/com/android/net/module/util/netlink/ConntrackMessage.java +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; - -import static com.android.net.module.util.netlink.StructNlAttr.findNextAttrOfType; -import static com.android.net.module.util.netlink.StructNlAttr.makeNestedType; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * A NetlinkMessage subclass for netlink conntrack messages. - * - * see also: <linux_src>/include/uapi/linux/netfilter/nfnetlink_conntrack.h - * - * @hide - */ -public class ConntrackMessage extends NetlinkMessage { - public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; - - // enum ctattr_type - public static final short CTA_TUPLE_ORIG = 1; - public static final short CTA_TUPLE_REPLY = 2; - public static final short CTA_STATUS = 3; - public static final short CTA_TIMEOUT = 7; - - // enum ctattr_tuple - public static final short CTA_TUPLE_IP = 1; - public static final short CTA_TUPLE_PROTO = 2; - - // enum ctattr_ip - public static final short CTA_IP_V4_SRC = 1; - public static final short CTA_IP_V4_DST = 2; - - // enum ctattr_l4proto - public static final short CTA_PROTO_NUM = 1; - public static final short CTA_PROTO_SRC_PORT = 2; - public static final short CTA_PROTO_DST_PORT = 3; - - // enum ip_conntrack_status - public static final int IPS_EXPECTED = 0x00000001; - public static final int IPS_SEEN_REPLY = 0x00000002; - public static final int IPS_ASSURED = 0x00000004; - public static final int IPS_CONFIRMED = 0x00000008; - public static final int IPS_SRC_NAT = 0x00000010; - public static final int IPS_DST_NAT = 0x00000020; - public static final int IPS_SEQ_ADJUST = 0x00000040; - public static final int IPS_SRC_NAT_DONE = 0x00000080; - public static final int IPS_DST_NAT_DONE = 0x00000100; - public static final int IPS_DYING = 0x00000200; - public static final int IPS_FIXED_TIMEOUT = 0x00000400; - public static final int IPS_TEMPLATE = 0x00000800; - public static final int IPS_UNTRACKED = 0x00001000; - public static final int IPS_HELPER = 0x00002000; - public static final int IPS_OFFLOAD = 0x00004000; - public static final int IPS_HW_OFFLOAD = 0x00008000; - - // ip_conntrack_status mask - // Interesting on the NAT conntrack session which has already seen two direction traffic. - // TODO: Probably IPS_{SRC, DST}_NAT_DONE are also interesting. - public static final int ESTABLISHED_MASK = IPS_CONFIRMED | IPS_ASSURED | IPS_SEEN_REPLY - | IPS_SRC_NAT; - // Interesting on the established NAT conntrack session which is dying. - public static final int DYING_MASK = ESTABLISHED_MASK | IPS_DYING; - - /** - * A tuple for the conntrack connection information. - * - * see also CTA_TUPLE_ORIG and CTA_TUPLE_REPLY. - */ - public static class Tuple { - public final Inet4Address srcIp; - public final Inet4Address dstIp; - - // Both port and protocol number are unsigned numbers stored in signed integers, and that - // callers that want to compare them to integers should either cast those integers, or - // convert them to unsigned using Byte.toUnsignedInt() and Short.toUnsignedInt(). - public final short srcPort; - public final short dstPort; - public final byte protoNum; - - public Tuple(TupleIpv4 ip, TupleProto proto) { - this.srcIp = ip.src; - this.dstIp = ip.dst; - this.srcPort = proto.srcPort; - this.dstPort = proto.dstPort; - this.protoNum = proto.protoNum; - } - - @Override - @VisibleForTesting - public boolean equals(Object o) { - if (!(o instanceof Tuple)) return false; - Tuple that = (Tuple) o; - return Objects.equals(this.srcIp, that.srcIp) - && Objects.equals(this.dstIp, that.dstIp) - && this.srcPort == that.srcPort - && this.dstPort == that.dstPort - && this.protoNum == that.protoNum; - } - - @Override - public int hashCode() { - return Objects.hash(srcIp, dstIp, srcPort, dstPort, protoNum); - } - - @Override - public String toString() { - final String srcIpStr = (srcIp == null) ? "null" : srcIp.getHostAddress(); - final String dstIpStr = (dstIp == null) ? "null" : dstIp.getHostAddress(); - final String protoStr = NetlinkConstants.stringForProtocol(protoNum); - - return "Tuple{" - + protoStr + ": " - + srcIpStr + ":" + Short.toUnsignedInt(srcPort) + " -> " - + dstIpStr + ":" + Short.toUnsignedInt(dstPort) - + "}"; - } - } - - /** - * A tuple for the conntrack connection address. - * - * see also CTA_TUPLE_IP. - */ - public static class TupleIpv4 { - public final Inet4Address src; - public final Inet4Address dst; - - public TupleIpv4(Inet4Address src, Inet4Address dst) { - this.src = src; - this.dst = dst; - } - } - - /** - * A tuple for the conntrack connection protocol. - * - * see also CTA_TUPLE_PROTO. - */ - public static class TupleProto { - public final byte protoNum; - public final short srcPort; - public final short dstPort; - - public TupleProto(byte protoNum, short srcPort, short dstPort) { - this.protoNum = protoNum; - this.srcPort = srcPort; - this.dstPort = dstPort; - } - } - - /** - * Create a netlink message to refresh IPv4 conntrack entry timeout. - */ - public static byte[] newIPv4TimeoutUpdateRequest( - int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) { - // *** STYLE WARNING *** - // - // Code below this point uses extra block indentation to highlight the - // packing of nested tuple netlink attribute types. - final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG, - new StructNlAttr(CTA_TUPLE_IP, - new StructNlAttr(CTA_IP_V4_SRC, src), - new StructNlAttr(CTA_IP_V4_DST, dst)), - new StructNlAttr(CTA_TUPLE_PROTO, - new StructNlAttr(CTA_PROTO_NUM, (byte) proto), - new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN), - new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN))); - - final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN); - - final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength(); - final byte[] bytes = new byte[STRUCT_SIZE + payloadLength]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final ConntrackMessage ctmsg = new ConntrackMessage(); - ctmsg.mHeader.nlmsg_len = bytes.length; - ctmsg.mHeader.nlmsg_type = (NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8) - | NetlinkConstants.IPCTNL_MSG_CT_NEW; - ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; - ctmsg.mHeader.nlmsg_seq = 1; - ctmsg.pack(byteBuffer); - - ctaTupleOrig.pack(byteBuffer); - ctaTimeout.pack(byteBuffer); - - return bytes; - } - - /** - * Parses a netfilter conntrack message from a {@link ByteBuffer}. - * - * @param header the netlink message header. - * @param byteBuffer The buffer from which to parse the netfilter conntrack message. - * @return the parsed netfilter conntrack message, or {@code null} if the netfilter conntrack - * message could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static ConntrackMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - // Just build the netlink header and netfilter header for now and pretend the whole message - // was consumed. - // TODO: Parse the conntrack attributes. - final StructNfGenMsg nfGenMsg = StructNfGenMsg.parse(byteBuffer); - if (nfGenMsg == null) { - return null; - } - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_STATUS, byteBuffer); - int status = 0; - if (nlAttr != null) { - status = nlAttr.getValueAsBe32(0); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(CTA_TIMEOUT, byteBuffer); - int timeoutSec = 0; - if (nlAttr != null) { - timeoutSec = nlAttr.getValueAsBe32(0); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_ORIG), byteBuffer); - Tuple tupleOrig = null; - if (nlAttr != null) { - tupleOrig = parseTuple(nlAttr.getValueAsByteBuffer()); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_REPLY), byteBuffer); - Tuple tupleReply = null; - if (nlAttr != null) { - tupleReply = parseTuple(nlAttr.getValueAsByteBuffer()); - } - - // Advance to the end of the message. - byteBuffer.position(baseOffset); - final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; - final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( - header.nlmsg_len - kMinConsumed); - if (byteBuffer.remaining() < kAdditionalSpace) { - return null; - } - byteBuffer.position(baseOffset + kAdditionalSpace); - - return new ConntrackMessage(header, nfGenMsg, tupleOrig, tupleReply, status, timeoutSec); - } - - /** - * Parses a conntrack tuple from a {@link ByteBuffer}. - * - * The attribute parsing is interesting on: - * - CTA_TUPLE_IP - * CTA_IP_V4_SRC - * CTA_IP_V4_DST - * - CTA_TUPLE_PROTO - * CTA_PROTO_NUM - * CTA_PROTO_SRC_PORT - * CTA_PROTO_DST_PORT - * - * Assume that the minimum size is the sum of CTA_TUPLE_IP (size: 20) and CTA_TUPLE_PROTO - * (size: 28). Here is an example for an expected CTA_TUPLE_ORIG message in raw data: - * +--------------------------------------------------------------------------------------+ - * | CTA_TUPLE_ORIG | - * +--------------------------+-----------------------------------------------------------+ - * | 1400 | nla_len = 20 | - * | 0180 | nla_type = nested CTA_TUPLE_IP | - * | 0800 0100 C0A8500C | nla_type=CTA_IP_V4_SRC, ip=192.168.80.12 | - * | 0800 0200 8C700874 | nla_type=CTA_IP_V4_DST, ip=140.112.8.116 | - * | 1C00 | nla_len = 28 | - * | 0280 | nla_type = nested CTA_TUPLE_PROTO | - * | 0500 0100 06 000000 | nla_type=CTA_PROTO_NUM, proto=IPPROTO_TCP (6) | - * | 0600 0200 F3F1 0000 | nla_type=CTA_PROTO_SRC_PORT, port=62449 (big endian) | - * | 0600 0300 01BB 0000 | nla_type=CTA_PROTO_DST_PORT, port=433 (big endian) | - * +--------------------------+-----------------------------------------------------------+ - * - * The position of the byte buffer doesn't set to the end when the function returns. It is okay - * because the caller ConntrackMessage#parse has passed a copy which is used for this parser - * only. Moreover, the parser behavior is the same as other existing netlink struct class - * parser. Ex: StructInetDiagMsg#parse. - */ - @Nullable - private static Tuple parseTuple(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - TupleIpv4 tupleIpv4 = null; - TupleProto tupleProto = null; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_IP), byteBuffer); - if (nlAttr != null) { - tupleIpv4 = parseTupleIpv4(nlAttr.getValueAsByteBuffer()); - } - if (tupleIpv4 == null) return null; - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(makeNestedType(CTA_TUPLE_PROTO), byteBuffer); - if (nlAttr != null) { - tupleProto = parseTupleProto(nlAttr.getValueAsByteBuffer()); - } - if (tupleProto == null) return null; - - return new Tuple(tupleIpv4, tupleProto); - } - - @Nullable - private static Inet4Address castToInet4Address(@Nullable InetAddress address) { - if (address == null || !(address instanceof Inet4Address)) return null; - return (Inet4Address) address; - } - - @Nullable - private static TupleIpv4 parseTupleIpv4(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - Inet4Address src = null; - Inet4Address dst = null; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_IP_V4_SRC, byteBuffer); - if (nlAttr != null) { - src = castToInet4Address(nlAttr.getValueAsInetAddress()); - } - if (src == null) return null; - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(CTA_IP_V4_DST, byteBuffer); - if (nlAttr != null) { - dst = castToInet4Address(nlAttr.getValueAsInetAddress()); - } - if (dst == null) return null; - - return new TupleIpv4(src, dst); - } - - @Nullable - private static TupleProto parseTupleProto(@Nullable ByteBuffer byteBuffer) { - if (byteBuffer == null) return null; - - byte protoNum = 0; - short srcPort = 0; - short dstPort = 0; - - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(CTA_PROTO_NUM, byteBuffer); - if (nlAttr != null) { - protoNum = nlAttr.getValueAsByte((byte) 0); - } - if (!(protoNum == IPPROTO_TCP || protoNum == IPPROTO_UDP)) return null; - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_SRC_PORT, byteBuffer); - if (nlAttr != null) { - srcPort = nlAttr.getValueAsBe16((short) 0); - } - if (srcPort == 0) return null; - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(CTA_PROTO_DST_PORT, byteBuffer); - if (nlAttr != null) { - dstPort = nlAttr.getValueAsBe16((short) 0); - } - if (dstPort == 0) return null; - - return new TupleProto(protoNum, srcPort, dstPort); - } - - /** - * Netfilter header. - */ - public final StructNfGenMsg nfGenMsg; - /** - * Original direction conntrack tuple. - * - * The tuple is determined by the parsed attribute value CTA_TUPLE_ORIG, or null if the - * tuple could not be parsed successfully (for example, if it was truncated or absent). - */ - @Nullable - public final Tuple tupleOrig; - /** - * Reply direction conntrack tuple. - * - * The tuple is determined by the parsed attribute value CTA_TUPLE_REPLY, or null if the - * tuple could not be parsed successfully (for example, if it was truncated or absent). - */ - @Nullable - public final Tuple tupleReply; - /** - * Connection status. A bitmask of ip_conntrack_status enum flags. - * - * The status is determined by the parsed attribute value CTA_STATUS, or 0 if the status could - * not be parsed successfully (for example, if it was truncated or absent). For the message - * from kernel, the valid status is non-zero. For the message from user space, the status may - * be 0 (absent). - */ - public final int status; - /** - * Conntrack timeout. - * - * The timeout is determined by the parsed attribute value CTA_TIMEOUT, or 0 if the timeout - * could not be parsed successfully (for example, if it was truncated or absent). For - * IPCTNL_MSG_CT_NEW event, the valid timeout is non-zero. For IPCTNL_MSG_CT_DELETE event, the - * timeout is 0 (absent). - */ - public final int timeoutSec; - - private ConntrackMessage() { - super(new StructNlMsgHdr()); - nfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET); - - // This constructor is only used by #newIPv4TimeoutUpdateRequest which doesn't use these - // data member for packing message. Simply fill them to null or 0. - tupleOrig = null; - tupleReply = null; - status = 0; - timeoutSec = 0; - } - - private ConntrackMessage(@NonNull StructNlMsgHdr header, @NonNull StructNfGenMsg nfGenMsg, - @Nullable Tuple tupleOrig, @Nullable Tuple tupleReply, int status, int timeoutSec) { - super(header); - this.nfGenMsg = nfGenMsg; - this.tupleOrig = tupleOrig; - this.tupleReply = tupleReply; - this.status = status; - this.timeoutSec = timeoutSec; - } - - /** - * Write a netfilter message to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - mHeader.pack(byteBuffer); - nfGenMsg.pack(byteBuffer); - } - - public short getMessageType() { - return (short) (getHeader().nlmsg_type & ~(NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8)); - } - - /** - * Convert an ip conntrack status to a string. - */ - public static String stringForIpConntrackStatus(int flags) { - final StringBuilder sb = new StringBuilder(); - - if ((flags & IPS_EXPECTED) != 0) { - sb.append("IPS_EXPECTED"); - } - if ((flags & IPS_SEEN_REPLY) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SEEN_REPLY"); - } - if ((flags & IPS_ASSURED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_ASSURED"); - } - if ((flags & IPS_CONFIRMED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_CONFIRMED"); - } - if ((flags & IPS_SRC_NAT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SRC_NAT"); - } - if ((flags & IPS_DST_NAT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DST_NAT"); - } - if ((flags & IPS_SEQ_ADJUST) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SEQ_ADJUST"); - } - if ((flags & IPS_SRC_NAT_DONE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_SRC_NAT_DONE"); - } - if ((flags & IPS_DST_NAT_DONE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DST_NAT_DONE"); - } - if ((flags & IPS_DYING) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_DYING"); - } - if ((flags & IPS_FIXED_TIMEOUT) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_FIXED_TIMEOUT"); - } - if ((flags & IPS_TEMPLATE) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_TEMPLATE"); - } - if ((flags & IPS_UNTRACKED) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_UNTRACKED"); - } - if ((flags & IPS_HELPER) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_HELPER"); - } - if ((flags & IPS_OFFLOAD) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_OFFLOAD"); - } - if ((flags & IPS_HW_OFFLOAD) != 0) { - if (sb.length() > 0) sb.append("|"); - sb.append("IPS_HW_OFFLOAD"); - } - return sb.toString(); - } - - @Override - public String toString() { - return "ConntrackMessage{" - + "nlmsghdr{" - + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_NETFILTER)) - + "}, " - + "nfgenmsg{" + nfGenMsg + "}, " - + "tuple_orig{" + tupleOrig + "}, " - + "tuple_reply{" + tupleReply + "}, " - + "status{" + status + "(" + stringForIpConntrackStatus(status) + ")" + "}, " - + "timeout_sec{" + Integer.toUnsignedLong(timeoutSec) + "}" - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/InetDiagMessage.java b/common/device/com/android/net/module/util/netlink/InetDiagMessage.java deleted file mode 100644 index f8b47164..00000000 --- a/common/device/com/android/net/module/util/netlink/InetDiagMessage.java +++ /dev/null @@ -1,505 +0,0 @@ -/* - * 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 com.android.net.module.util.netlink; - -import static android.os.Process.INVALID_UID; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.ENOENT; -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.NETLINK_INET_DIAG; - -import static com.android.net.module.util.netlink.NetlinkConstants.NLMSG_DONE; -import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DESTROY; -import static com.android.net.module.util.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; -import static com.android.net.module.util.netlink.NetlinkConstants.hexify; -import static com.android.net.module.util.netlink.NetlinkConstants.stringForAddressFamily; -import static com.android.net.module.util.netlink.NetlinkConstants.stringForProtocol; -import static com.android.net.module.util.netlink.NetlinkUtils.DEFAULT_RECV_BUFSIZE; -import static com.android.net.module.util.netlink.NetlinkUtils.IO_TIMEOUT_MS; -import static com.android.net.module.util.netlink.NetlinkUtils.TCP_ALIVE_STATE_FILTER; -import static com.android.net.module.util.netlink.NetlinkUtils.connectSocketToNetlink; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.net.util.SocketUtils; -import android.os.Process; -import android.os.SystemClock; -import android.system.ErrnoException; -import android.util.Log; -import android.util.Range; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -/** - * A NetlinkMessage subclass for netlink inet_diag messages. - * - * see also: <linux_src>/include/uapi/linux/inet_diag.h - * - * @hide - */ -public class InetDiagMessage extends NetlinkMessage { - public static final String TAG = "InetDiagMessage"; - private static final int TIMEOUT_MS = 500; - - /** - * Construct an inet_diag_req_v2 message. This method will throw - * {@link IllegalArgumentException} if local and remote are not both null or both non-null. - */ - public static byte[] inetDiagReqV2(int protocol, InetSocketAddress local, - InetSocketAddress remote, int family, short flags) { - return inetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */, - 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES); - } - - /** - * Construct an inet_diag_req_v2 message. This method will throw - * {@code IllegalArgumentException} if local and remote are not both null or both non-null. - * - * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, - * IPPROTO_UDP, or IPPROTO_UDPLITE. - * @param local local socket address of the target socket. This will be packed into a - * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of - * local or remote address is null. - * @param remote remote socket address of the target socket. This will be packed into a - * {@link StructInetDiagSockId}. Request to diagnose for all sockets if both of - * local or remote address is null. - * @param family the ip family of the request message. This should be set to either AF_INET or - * AF_INET6 for IPv4 or IPv6 sockets respectively. - * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. - * @param pad for raw socket protocol specification. - * @param idiagExt a set of flags defining what kind of extended information to report. - * @param state a bit mask that defines a filter of socket states. - * - * @return bytes array representation of the message - */ - public static byte[] inetDiagReqV2(int protocol, @Nullable InetSocketAddress local, - @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, - int state) throws IllegalArgumentException { - // Request for all sockets if no specific socket is requested. Specify the local and remote - // socket address information for target request socket. - if ((local == null) != (remote == null)) { - throw new IllegalArgumentException( - "Local and remote must be both null or both non-null"); - } - final StructInetDiagSockId id = ((local != null && remote != null) - ? new StructInetDiagSockId(local, remote) : null); - return inetDiagReqV2(protocol, id, family, - SOCK_DIAG_BY_FAMILY, flags, pad, idiagExt, state); - } - - /** - * Construct an inet_diag_req_v2 message. - * - * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, - * IPPROTO_UDP, or IPPROTO_UDPLITE. - * @param id inet_diag_sockid. See {@link StructInetDiagSockId} - * @param family the ip family of the request message. This should be set to either AF_INET or - * AF_INET6 for IPv4 or IPv6 sockets respectively. - * @param type message types. - * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. - * @param pad for raw socket protocol specification. - * @param idiagExt a set of flags defining what kind of extended information to report. - * @param state a bit mask that defines a filter of socket states. - * @return bytes array representation of the message - */ - public static byte[] inetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, - short type, short flags, int pad, int idiagExt, int state) { - final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr(); - nlMsgHdr.nlmsg_len = bytes.length; - nlMsgHdr.nlmsg_type = type; - nlMsgHdr.nlmsg_flags = flags; - nlMsgHdr.pack(byteBuffer); - final StructInetDiagReqV2 inetDiagReqV2 = - new StructInetDiagReqV2(protocol, id, family, pad, idiagExt, state); - - inetDiagReqV2.pack(byteBuffer); - return bytes; - } - - public StructInetDiagMsg inetDiagMsg; - - @VisibleForTesting - public InetDiagMessage(@NonNull StructNlMsgHdr header) { - super(header); - inetDiagMsg = new StructInetDiagMsg(); - } - - /** - * Parse an inet_diag_req_v2 message from buffer. - */ - @Nullable - public static InetDiagMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - final InetDiagMessage msg = new InetDiagMessage(header); - msg.inetDiagMsg = StructInetDiagMsg.parse(byteBuffer); - if (msg.inetDiagMsg == null) { - return null; - } - return msg; - } - - private static void closeSocketQuietly(final FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - - private static int lookupUidByFamily(int protocol, InetSocketAddress local, - InetSocketAddress remote, int family, short flags, - FileDescriptor fd) - throws ErrnoException, InterruptedIOException { - byte[] msg = inetDiagReqV2(protocol, local, remote, family, flags); - NetlinkUtils.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); - ByteBuffer response = NetlinkUtils.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); - - final NetlinkMessage nlMsg = NetlinkMessage.parse(response, NETLINK_INET_DIAG); - if (nlMsg == null) { - return INVALID_UID; - } - final StructNlMsgHdr hdr = nlMsg.getHeader(); - if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { - return INVALID_UID; - } - if (nlMsg instanceof InetDiagMessage) { - return ((InetDiagMessage) nlMsg).inetDiagMsg.idiag_uid; - } - return INVALID_UID; - } - - private static final int[] FAMILY = {AF_INET6, AF_INET}; - - private static int lookupUid(int protocol, InetSocketAddress local, - InetSocketAddress remote, FileDescriptor fd) - throws ErrnoException, InterruptedIOException { - int uid; - - for (int family : FAMILY) { - /** - * For exact match lookup, swap local and remote for UDP lookups due to kernel - * bug which will not be fixed. See aosp/755889 and - * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html - */ - if (protocol == IPPROTO_UDP) { - uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd); - } else { - uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd); - } - if (uid != INVALID_UID) { - return uid; - } - } - - /** - * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the - * socket is not connected (and even if the socket is connected to a different destination). - * If we want this API to work for such packets, then on miss we need to do a second lookup - * with only the local address and port filled in. - * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard. - */ - if (protocol == IPPROTO_UDP) { - try { - InetSocketAddress wildcard = new InetSocketAddress( - Inet6Address.getByName("::"), 0); - uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6, - (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); - if (uid != INVALID_UID) { - return uid; - } - wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0); - uid = lookupUidByFamily(protocol, local, wildcard, AF_INET, - (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); - if (uid != INVALID_UID) { - return uid; - } - } catch (UnknownHostException e) { - Log.e(TAG, e.toString()); - } - } - return INVALID_UID; - } - - /** - * Use an inet_diag socket to look up the UID associated with the input local and remote - * address/port and protocol of a connection. - */ - public static int getConnectionOwnerUid(int protocol, InetSocketAddress local, - InetSocketAddress remote) { - int uid = INVALID_UID; - FileDescriptor fd = null; - try { - fd = NetlinkUtils.netlinkSocketForProto(NETLINK_INET_DIAG); - NetlinkUtils.connectSocketToNetlink(fd); - uid = lookupUid(protocol, local, remote, fd); - } catch (ErrnoException | SocketException | IllegalArgumentException - | InterruptedIOException e) { - Log.e(TAG, e.toString()); - } finally { - closeSocketQuietly(fd); - } - return uid; - } - - /** - * Construct an inet_diag_req_v2 message for querying alive TCP sockets from kernel. - */ - public static byte[] buildInetDiagReqForAliveTcpSockets(int family) { - return inetDiagReqV2(IPPROTO_TCP, - null /* local addr */, - null /* remote addr */, - family, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP) /* flag */, - 0 /* pad */, - 1 << NetlinkConstants.INET_DIAG_MEMINFO /* idiagExt */, - TCP_ALIVE_STATE_FILTER); - } - - private static void sendNetlinkDestroyRequest(FileDescriptor fd, int proto, - InetDiagMessage diagMsg) throws InterruptedIOException, ErrnoException { - final byte[] destroyMsg = InetDiagMessage.inetDiagReqV2( - proto, - diagMsg.inetDiagMsg.id, - diagMsg.inetDiagMsg.idiag_family, - SOCK_DESTROY, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_ACK), - 0 /* pad */, - 0 /* idiagExt */, - 1 << diagMsg.inetDiagMsg.idiag_state - ); - NetlinkUtils.sendMessage(fd, destroyMsg, 0, destroyMsg.length, IO_TIMEOUT_MS); - NetlinkUtils.receiveNetlinkAck(fd); - } - - private static void sendNetlinkDumpRequest(FileDescriptor fd, int proto, int states, int family) - throws InterruptedIOException, ErrnoException { - final byte[] dumpMsg = InetDiagMessage.inetDiagReqV2( - proto, - null /* id */, - family, - SOCK_DIAG_BY_FAMILY, - (short) (StructNlMsgHdr.NLM_F_REQUEST | StructNlMsgHdr.NLM_F_DUMP), - 0 /* pad */, - 0 /* idiagExt */, - states); - NetlinkUtils.sendMessage(fd, dumpMsg, 0, dumpMsg.length, IO_TIMEOUT_MS); - } - - private static int processNetlinkDumpAndDestroySockets(FileDescriptor dumpFd, - FileDescriptor destroyFd, int proto, Predicate<InetDiagMessage> filter) - throws InterruptedIOException, ErrnoException { - int destroyedSockets = 0; - - while (true) { - final ByteBuffer buf = NetlinkUtils.recvMessage( - dumpFd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - - while (buf.remaining() > 0) { - final int position = buf.position(); - final NetlinkMessage nlMsg = NetlinkMessage.parse(buf, NETLINK_INET_DIAG); - if (nlMsg == null) { - // Move to the position where parse started for error log. - buf.position(position); - Log.e(TAG, "Failed to parse netlink message: " + hexify(buf)); - break; - } - - if (nlMsg.getHeader().nlmsg_type == NLMSG_DONE) { - return destroyedSockets; - } - - if (!(nlMsg instanceof InetDiagMessage)) { - Log.wtf(TAG, "Received unexpected netlink message: " + nlMsg); - continue; - } - - final InetDiagMessage diagMsg = (InetDiagMessage) nlMsg; - if (filter.test(diagMsg)) { - try { - sendNetlinkDestroyRequest(destroyFd, proto, diagMsg); - destroyedSockets++; - } catch (InterruptedIOException | ErrnoException e) { - if (!(e instanceof ErrnoException - && ((ErrnoException) e).errno == ENOENT)) { - Log.e(TAG, "Failed to destroy socket: diagMsg=" + diagMsg + ", " + e); - } - } - } - } - } - } - - /** - * Returns whether the InetDiagMessage is for adb socket or not - */ - @VisibleForTesting - public static boolean isAdbSocket(final InetDiagMessage msg) { - // This is inaccurate since adb could run with ROOT_UID or other services can run with - // SHELL_UID. But this check covers most cases and enough. - // Note that getting service.adb.tcp.port system property is prohibited by sepolicy - // TODO: skip the socket only if there is a listen socket owned by SHELL_UID with the same - // source port as this socket - return msg.inetDiagMsg.idiag_uid == Process.SHELL_UID; - } - - /** - * Returns whether the range contains the uid in the InetDiagMessage or not - */ - @VisibleForTesting - public static boolean containsUid(InetDiagMessage msg, Set<Range<Integer>> ranges) { - for (final Range<Integer> range: ranges) { - if (range.contains(msg.inetDiagMsg.idiag_uid)) { - return true; - } - } - return false; - } - - private static boolean isLoopbackAddress(InetAddress addr) { - if (addr.isLoopbackAddress()) return true; - if (!(addr instanceof Inet6Address)) return false; - - // Following check is for v4-mapped v6 address. StructInetDiagSockId contains v4-mapped v6 - // address as Inet6Address, See StructInetDiagSockId#parse - final byte[] addrBytes = addr.getAddress(); - for (int i = 0; i < 10; i++) { - if (addrBytes[i] != 0) return false; - } - return addrBytes[10] == (byte) 0xff - && addrBytes[11] == (byte) 0xff - && addrBytes[12] == 127; - } - - /** - * Returns whether the socket address in the InetDiagMessage is loopback or not - */ - @VisibleForTesting - public static boolean isLoopback(InetDiagMessage msg) { - final InetAddress srcAddr = msg.inetDiagMsg.id.locSocketAddress.getAddress(); - final InetAddress dstAddr = msg.inetDiagMsg.id.remSocketAddress.getAddress(); - return isLoopbackAddress(srcAddr) - || isLoopbackAddress(dstAddr) - || srcAddr.equals(dstAddr); - } - - private static void destroySockets(int proto, int states, Predicate<InetDiagMessage> filter) - throws ErrnoException, SocketException, InterruptedIOException { - FileDescriptor dumpFd = null; - FileDescriptor destroyFd = null; - - try { - dumpFd = NetlinkUtils.createNetLinkInetDiagSocket(); - destroyFd = NetlinkUtils.createNetLinkInetDiagSocket(); - connectSocketToNetlink(dumpFd); - connectSocketToNetlink(destroyFd); - - for (int family : List.of(AF_INET, AF_INET6)) { - try { - sendNetlinkDumpRequest(dumpFd, proto, states, family); - } catch (InterruptedIOException | ErrnoException e) { - Log.e(TAG, "Failed to send netlink dump request: " + e); - continue; - } - final int destroyedSockets = processNetlinkDumpAndDestroySockets( - dumpFd, destroyFd, proto, filter); - Log.d(TAG, "Destroyed " + destroyedSockets + " sockets" - + ", proto=" + stringForProtocol(proto) - + ", family=" + stringForAddressFamily(family) - + ", states=" + states); - } - } finally { - closeSocketQuietly(dumpFd); - closeSocketQuietly(destroyFd); - } - } - - /** - * Close tcp sockets that match the following condition - * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV - * 2. Owner uid of socket is not in the exemptUids - * 3. Owner uid of socket is in the ranges - * 4. Socket is not loopback - * 5. Socket is not adb socket - * - * @param ranges target uid ranges - * @param exemptUids uids to skip close socket - */ - public static void destroyLiveTcpSockets(Set<Range<Integer>> ranges, Set<Integer> exemptUids) - throws SocketException, InterruptedIOException, ErrnoException { - final long startTimeMs = SystemClock.elapsedRealtime(); - destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, - (diagMsg) -> !exemptUids.contains(diagMsg.inetDiagMsg.idiag_uid) - && containsUid(diagMsg, ranges) - && !isLoopback(diagMsg) - && !isAdbSocket(diagMsg)); - final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; - Log.d(TAG, "Destroyed live tcp sockets for uids=" + ranges + " exemptUids=" + exemptUids - + " in " + durationMs + "ms"); - } - - /** - * Close tcp sockets that match the following condition - * 1. TCP status is one of TCP_ESTABLISHED, TCP_SYN_SENT, and TCP_SYN_RECV - * 2. Owner uid of socket is in the targetUids - * 3. Socket is not loopback - * 4. Socket is not adb socket - * - * @param ownerUids target uids to close sockets - */ - public static void destroyLiveTcpSocketsByOwnerUids(Set<Integer> ownerUids) - throws SocketException, InterruptedIOException, ErrnoException { - final long startTimeMs = SystemClock.elapsedRealtime(); - destroySockets(IPPROTO_TCP, TCP_ALIVE_STATE_FILTER, - (diagMsg) -> ownerUids.contains(diagMsg.inetDiagMsg.idiag_uid) - && !isLoopback(diagMsg) - && !isAdbSocket(diagMsg)); - final long durationMs = SystemClock.elapsedRealtime() - startTimeMs; - Log.d(TAG, "Destroyed live tcp sockets for uids=" + ownerUids + " in " + durationMs + "ms"); - } - - @Override - public String toString() { - return "InetDiagMessage{ " - + "nlmsghdr{" - + (mHeader == null ? "" : mHeader.toString(NETLINK_INET_DIAG)) + "}, " - + "inet_diag_msg{" - + (inetDiagMsg == null ? "" : inetDiagMsg.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/NdOption.java b/common/device/com/android/net/module/util/netlink/NdOption.java deleted file mode 100644 index defc88a7..00000000 --- a/common/device/com/android/net/module/util/netlink/NdOption.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; - -import java.nio.ByteBuffer; - -/** - * Base class for IPv6 neighbour discovery options. - */ -public class NdOption { - public static final int STRUCT_SIZE = 2; - - /** The option type. */ - public final byte type; - /** The length of the option in 8-byte units. Actually an unsigned 8-bit integer */ - public final int length; - - /** Constructs a new NdOption. */ - NdOption(byte type, int length) { - this.type = type; - this.length = length; - } - - /** - * Parses a neighbour discovery option. - * - * Parses (and consumes) the option if it is of a known type. If the option is of an unknown - * type, advances the buffer (so the caller can continue parsing if desired) and returns - * {@link #UNKNOWN}. If the option claims a length of 0, returns null because parsing cannot - * continue. - * - * No checks are performed on the length other than ensuring it is not 0, so if a caller wants - * to deal with options that might overflow the structure that contains them, it must explicitly - * set the buffer's limit to the position at which that structure ends. - * - * @param buf the buffer to parse. - * @return a subclass of {@link NdOption}, or {@code null} for an unknown or malformed option. - */ - public static NdOption parse(@NonNull ByteBuffer buf) { - if (buf.remaining() < STRUCT_SIZE) return null; - - // Peek the type without advancing the buffer. - byte type = buf.get(buf.position()); - int length = Byte.toUnsignedInt(buf.get(buf.position() + 1)); - if (length == 0) return null; - - switch (type) { - case StructNdOptPref64.TYPE: - return StructNdOptPref64.parse(buf); - - case StructNdOptRdnss.TYPE: - return StructNdOptRdnss.parse(buf); - - default: - int newPosition = Math.min(buf.limit(), buf.position() + length * 8); - buf.position(newPosition); - return UNKNOWN; - } - } - - void writeToByteBuffer(ByteBuffer buf) { - buf.put(type); - buf.put((byte) length); - } - - @Override - public String toString() { - return String.format("NdOption(%d, %d)", Byte.toUnsignedInt(type), length); - } - - public static final NdOption UNKNOWN = new NdOption((byte) 0, 0); -} diff --git a/common/device/com/android/net/module/util/netlink/NduseroptMessage.java b/common/device/com/android/net/module/util/netlink/NduseroptMessage.java deleted file mode 100644 index bdf574db..00000000 --- a/common/device/com/android/net/module/util/netlink/NduseroptMessage.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET6; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A NetlinkMessage subclass for RTM_NEWNDUSEROPT messages. - */ -public class NduseroptMessage extends NetlinkMessage { - public static final int STRUCT_SIZE = 16; - - static final int NDUSEROPT_SRCADDR = 1; - - /** The address family. Presumably always AF_INET6. */ - public final byte family; - /** - * The total length in bytes of the options that follow this structure. - * Actually a 16-bit unsigned integer. - */ - public final int opts_len; - /** The interface index on which the options were received. */ - public final int ifindex; - /** The ICMP type of the packet that contained the options. */ - public final byte icmp_type; - /** The ICMP code of the packet that contained the options. */ - public final byte icmp_code; - - /** - * ND option that was in this message. - * Even though the length field is called "opts_len", the kernel only ever sends one option per - * message. It is unlikely that this will ever change as it would break existing userspace code. - * But if it does, we can simply update this code, since userspace is typically newer than the - * kernel. - */ - @Nullable - public final NdOption option; - - /** The IP address that sent the packet containing the option. */ - public final InetAddress srcaddr; - - NduseroptMessage(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) - throws UnknownHostException { - super(header); - - // The structure itself. - buf.order(ByteOrder.nativeOrder()); // Restored in the finally clause inside parse(). - final int start = buf.position(); - family = buf.get(); - buf.get(); // Skip 1 byte of padding. - opts_len = Short.toUnsignedInt(buf.getShort()); - ifindex = buf.getInt(); - icmp_type = buf.get(); - icmp_code = buf.get(); - buf.position(buf.position() + 6); // Skip 6 bytes of padding. - - // The ND option. - // Ensure we don't read past opts_len even if the option length is invalid. - // Note that this check is not really necessary since if the option length is not valid, - // this struct won't be very useful to the caller. - // - // It's safer to pass the slice of original ByteBuffer to just parse the ND option field, - // although parsing ND option might throw exception or return null, it won't break the - // original ByteBuffer position. - buf.order(ByteOrder.BIG_ENDIAN); - try { - final ByteBuffer slice = buf.slice(); - slice.limit(opts_len); - option = NdOption.parse(slice); - } finally { - // Advance buffer position according to opts_len in the header. ND option length might - // be incorrect in the malformed packet. - int newPosition = start + STRUCT_SIZE + opts_len; - if (newPosition >= buf.limit()) { - throw new IllegalArgumentException("ND option extends past end of buffer"); - } - buf.position(newPosition); - } - - // The source address attribute. - StructNlAttr nla = StructNlAttr.parse(buf); - if (nla == null || nla.nla_type != NDUSEROPT_SRCADDR || nla.nla_value == null) { - throw new IllegalArgumentException("Invalid source address in ND useropt"); - } - if (family == AF_INET6) { - // InetAddress.getByAddress only looks at the ifindex if the address type needs one. - srcaddr = Inet6Address.getByAddress(null /* hostname */, nla.nla_value, ifindex); - } else { - srcaddr = InetAddress.getByAddress(nla.nla_value); - } - } - - /** - * Parses a StructNduseroptmsg from a {@link ByteBuffer}. - * - * @param header the netlink message header. - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully - * (for example, if it was truncated, or if the prefix length code was wrong). - */ - @Nullable - public static NduseroptMessage parse(@NonNull StructNlMsgHdr header, @NonNull ByteBuffer buf) { - if (buf == null || buf.remaining() < STRUCT_SIZE) return null; - ByteOrder oldOrder = buf.order(); - try { - return new NduseroptMessage(header, buf); - } catch (IllegalArgumentException | UnknownHostException | BufferUnderflowException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated, so - // callers must already handle it. - return null; - } finally { - buf.order(oldOrder); - } - } - - @Override - public String toString() { - return String.format("Nduseroptmsg(%d, %d, %d, %d, %d, %s)", - family, opts_len, ifindex, Byte.toUnsignedInt(icmp_type), - Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress()); - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java b/common/device/com/android/net/module/util/netlink/NetlinkConstants.java deleted file mode 100644 index 44c51d8a..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkConstants.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2015 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 com.android.net.module.util.netlink; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; - -import java.nio.ByteBuffer; - -/** - * Various constants and static helper methods for netlink communications. - * - * Values taken from: - * - * include/uapi/linux/netfilter/nfnetlink.h - * include/uapi/linux/netfilter/nfnetlink_conntrack.h - * include/uapi/linux/netlink.h - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class NetlinkConstants { - private NetlinkConstants() {} - - public static final int NLA_ALIGNTO = 4; - /** - * Flag for dumping struct tcp_info. - * Corresponding to enum definition in external/strace/linux/inet_diag.h. - */ - public static final int INET_DIAG_MEMINFO = 1; - - public static final int SOCKDIAG_MSG_HEADER_SIZE = - StructNlMsgHdr.STRUCT_SIZE + StructInetDiagMsg.STRUCT_SIZE; - - /** - * Get the aligned length based on a Short type number. - */ - public static final int alignedLengthOf(short length) { - final int intLength = (int) length & 0xffff; - return alignedLengthOf(intLength); - } - - /** - * Get the aligned length based on a Integer type number. - */ - public static final int alignedLengthOf(int length) { - if (length <= 0) return 0; - return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); - } - - /** - * Convert a address family type to a string. - */ - public static String stringForAddressFamily(int family) { - if (family == OsConstants.AF_INET) return "AF_INET"; - if (family == OsConstants.AF_INET6) return "AF_INET6"; - if (family == OsConstants.AF_NETLINK) return "AF_NETLINK"; - if (family == OsConstants.AF_UNSPEC) return "AF_UNSPEC"; - return String.valueOf(family); - } - - /** - * Convert a protocol type to a string. - */ - public static String stringForProtocol(int protocol) { - if (protocol == OsConstants.IPPROTO_TCP) return "IPPROTO_TCP"; - if (protocol == OsConstants.IPPROTO_UDP) return "IPPROTO_UDP"; - return String.valueOf(protocol); - } - - /** - * Convert a byte array to a hexadecimal string. - */ - public static String hexify(byte[] bytes) { - if (bytes == null) return "(null)"; - return toHexString(bytes, 0, bytes.length); - } - - /** - * Convert a {@link ByteBuffer} to a hexadecimal string. - */ - public static String hexify(ByteBuffer buffer) { - if (buffer == null) return "(null)"; - return toHexString( - buffer.array(), buffer.position(), buffer.remaining()); - } - - // Known values for struct nlmsghdr nlm_type. - public static final short NLMSG_NOOP = 1; // Nothing - public static final short NLMSG_ERROR = 2; // Error - public static final short NLMSG_DONE = 3; // End of a dump - public static final short NLMSG_OVERRUN = 4; // Data lost - public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value - - public static final short RTM_NEWLINK = 16; - public static final short RTM_DELLINK = 17; - public static final short RTM_GETLINK = 18; - public static final short RTM_SETLINK = 19; - public static final short RTM_NEWADDR = 20; - public static final short RTM_DELADDR = 21; - public static final short RTM_GETADDR = 22; - public static final short RTM_NEWROUTE = 24; - public static final short RTM_DELROUTE = 25; - public static final short RTM_GETROUTE = 26; - public static final short RTM_NEWNEIGH = 28; - public static final short RTM_DELNEIGH = 29; - public static final short RTM_GETNEIGH = 30; - public static final short RTM_NEWRULE = 32; - public static final short RTM_DELRULE = 33; - public static final short RTM_GETRULE = 34; - public static final short RTM_NEWNDUSEROPT = 68; - - // Netfilter netlink message types are presented by two bytes: high byte subsystem and - // low byte operation. See the macro NFNL_SUBSYS_ID and NFNL_MSG_TYPE in - // include/uapi/linux/netfilter/nfnetlink.h - public static final short NFNL_SUBSYS_CTNETLINK = 1; - - public static final short IPCTNL_MSG_CT_NEW = 0; - public static final short IPCTNL_MSG_CT_GET = 1; - public static final short IPCTNL_MSG_CT_DELETE = 2; - public static final short IPCTNL_MSG_CT_GET_CTRZERO = 3; - public static final short IPCTNL_MSG_CT_GET_STATS_CPU = 4; - public static final short IPCTNL_MSG_CT_GET_STATS = 5; - public static final short IPCTNL_MSG_CT_GET_DYING = 6; - public static final short IPCTNL_MSG_CT_GET_UNCONFIRMED = 7; - - /* see include/uapi/linux/sock_diag.h */ - public static final short SOCK_DIAG_BY_FAMILY = 20; - public static final short SOCK_DESTROY = 21; - - // Netlink groups. - public static final int RTMGRP_LINK = 1; - public static final int RTMGRP_IPV4_IFADDR = 0x10; - public static final int RTMGRP_IPV6_IFADDR = 0x100; - public static final int RTMGRP_IPV6_ROUTE = 0x400; - public static final int RTNLGRP_ND_USEROPT = 20; - public static final int RTMGRP_ND_USEROPT = 1 << (RTNLGRP_ND_USEROPT - 1); - - // Device flags. - public static final int IFF_UP = 1 << 0; - public static final int IFF_LOWER_UP = 1 << 16; - - // Known values for struct rtmsg rtm_protocol. - public static final short RTPROT_KERNEL = 2; - public static final short RTPROT_RA = 9; - - // Known values for struct rtmsg rtm_scope. - public static final short RT_SCOPE_UNIVERSE = 0; - - // Known values for struct rtmsg rtm_type. - public static final short RTN_UNICAST = 1; - - // Known values for struct rtmsg rtm_flags. - public static final int RTM_F_CLONED = 0x200; - - /** - * Convert a netlink message type to a string for control message. - */ - @NonNull - private static String stringForCtlMsgType(short nlmType) { - switch (nlmType) { - case NLMSG_NOOP: return "NLMSG_NOOP"; - case NLMSG_ERROR: return "NLMSG_ERROR"; - case NLMSG_DONE: return "NLMSG_DONE"; - case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; - default: return "unknown control message type: " + String.valueOf(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_ROUTE. - */ - @NonNull - private static String stringForRtMsgType(short nlmType) { - switch (nlmType) { - case RTM_NEWLINK: return "RTM_NEWLINK"; - case RTM_DELLINK: return "RTM_DELLINK"; - case RTM_GETLINK: return "RTM_GETLINK"; - case RTM_SETLINK: return "RTM_SETLINK"; - case RTM_NEWADDR: return "RTM_NEWADDR"; - case RTM_DELADDR: return "RTM_DELADDR"; - case RTM_GETADDR: return "RTM_GETADDR"; - case RTM_NEWROUTE: return "RTM_NEWROUTE"; - case RTM_DELROUTE: return "RTM_DELROUTE"; - case RTM_GETROUTE: return "RTM_GETROUTE"; - case RTM_NEWNEIGH: return "RTM_NEWNEIGH"; - case RTM_DELNEIGH: return "RTM_DELNEIGH"; - case RTM_GETNEIGH: return "RTM_GETNEIGH"; - case RTM_NEWRULE: return "RTM_NEWRULE"; - case RTM_DELRULE: return "RTM_DELRULE"; - case RTM_GETRULE: return "RTM_GETRULE"; - case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT"; - default: return "unknown RTM type: " + String.valueOf(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_INET_DIAG. - */ - @NonNull - private static String stringForInetDiagMsgType(short nlmType) { - switch (nlmType) { - case SOCK_DIAG_BY_FAMILY: return "SOCK_DIAG_BY_FAMILY"; - default: return "unknown SOCK_DIAG type: " + String.valueOf(nlmType); - } - } - - /** - * Convert a netlink message type to a string for NETLINK_NETFILTER. - */ - @NonNull - private static String stringForNfMsgType(short nlmType) { - final byte subsysId = (byte) (nlmType >> 8); - final byte msgType = (byte) nlmType; - switch (subsysId) { - case NFNL_SUBSYS_CTNETLINK: - switch (msgType) { - case IPCTNL_MSG_CT_NEW: return "IPCTNL_MSG_CT_NEW"; - case IPCTNL_MSG_CT_GET: return "IPCTNL_MSG_CT_GET"; - case IPCTNL_MSG_CT_DELETE: return "IPCTNL_MSG_CT_DELETE"; - case IPCTNL_MSG_CT_GET_CTRZERO: return "IPCTNL_MSG_CT_GET_CTRZERO"; - case IPCTNL_MSG_CT_GET_STATS_CPU: return "IPCTNL_MSG_CT_GET_STATS_CPU"; - case IPCTNL_MSG_CT_GET_STATS: return "IPCTNL_MSG_CT_GET_STATS"; - case IPCTNL_MSG_CT_GET_DYING: return "IPCTNL_MSG_CT_GET_DYING"; - case IPCTNL_MSG_CT_GET_UNCONFIRMED: return "IPCTNL_MSG_CT_GET_UNCONFIRMED"; - } - break; - } - return "unknown NETFILTER type: " + String.valueOf(nlmType); - } - - /** - * Convert a netlink message type to a string by netlink family. - */ - @NonNull - public static String stringForNlMsgType(short nlmType, int nlFamily) { - // Reserved control messages. The netlink family is ignored. - // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. - if (nlmType <= NLMSG_MAX_RESERVED) return stringForCtlMsgType(nlmType); - - // Netlink family messages. The netlink family is required. Note that the reason for using - // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are - // not constant. - if (nlFamily == OsConstants.NETLINK_ROUTE) return stringForRtMsgType(nlmType); - if (nlFamily == OsConstants.NETLINK_INET_DIAG) return stringForInetDiagMsgType(nlmType); - if (nlFamily == OsConstants.NETLINK_NETFILTER) return stringForNfMsgType(nlmType); - - return "unknown type: " + String.valueOf(nlmType); - } - - private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F' }; - /** - * Convert a byte array to a hexadecimal string. - */ - public static String toHexString(byte[] array, int offset, int length) { - char[] buf = new char[length * 2]; - - int bufIndex = 0; - for (int i = offset; i < offset + length; i++) { - byte b = array[i]; - buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; - buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; - } - - return new String(buf); - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java b/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java deleted file mode 100644 index 48314323..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkErrorMessage.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for netlink error messages. - * - * @hide - */ -public class NetlinkErrorMessage extends NetlinkMessage { - - /** - * Parse a netlink error message from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink error message. - * @return the parsed netlink error message, or {@code null} if the netlink error message - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static NetlinkErrorMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header); - - errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer); - if (errorMsg.mNlMsgErr == null) { - return null; - } - - return errorMsg; - } - - private StructNlMsgErr mNlMsgErr; - - NetlinkErrorMessage(@NonNull StructNlMsgHdr header) { - super(header); - mNlMsgErr = null; - } - - public StructNlMsgErr getNlMsgError() { - return mNlMsgErr; - } - - @Override - public String toString() { - return "NetlinkErrorMessage{ " - + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " - + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java b/common/device/com/android/net/module/util/netlink/NetlinkMessage.java deleted file mode 100644 index 9e1e26e7..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkMessage.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * NetlinkMessage base class for other, more specific netlink message types. - * - * Classes that extend NetlinkMessage should: - * - implement a public static parse(StructNlMsgHdr, ByteBuffer) method - * - returning either null (parse errors) or a new object of the subclass - * type (cast-able to NetlinkMessage) - * - * NetlinkMessage.parse() should be updated to know which nlmsg_type values - * correspond with which message subclasses. - * - * @hide - */ -public class NetlinkMessage { - private static final String TAG = "NetlinkMessage"; - - /** - * Parsing netlink messages for reserved control message or specific netlink message. The - * netlink family is required for parsing specific netlink message. See man-pages/netlink. - */ - @Nullable - public static NetlinkMessage parse(@NonNull ByteBuffer byteBuffer, int nlFamily) { - final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); - if (nlmsghdr == null) { - return null; - } - - final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; - if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) { - // Malformed message or runt buffer. Pretend the buffer was consumed. - byteBuffer.position(byteBuffer.limit()); - return null; - } - - // Reserved control messages. The netlink family is ignored. - // See NLMSG_MIN_TYPE in include/uapi/linux/netlink.h. - if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { - return parseCtlMessage(nlmsghdr, byteBuffer, payloadLength); - } - - // Netlink family messages. The netlink family is required. Note that the reason for using - // if-statement is that switch-case can't be used because the OsConstants.NETLINK_* are - // not constant. - final NetlinkMessage parsed; - if (nlFamily == OsConstants.NETLINK_ROUTE) { - parsed = parseRtMessage(nlmsghdr, byteBuffer); - } else if (nlFamily == OsConstants.NETLINK_INET_DIAG) { - parsed = parseInetDiagMessage(nlmsghdr, byteBuffer); - } else if (nlFamily == OsConstants.NETLINK_NETFILTER) { - parsed = parseNfMessage(nlmsghdr, byteBuffer); - } else { - parsed = null; - } - - // Advance to the end of the message, regardless of whether the parsing code consumed - // all of it or not. - byteBuffer.position(startPosition + messageLength); - - return parsed; - } - - @NonNull - protected final StructNlMsgHdr mHeader; - - public NetlinkMessage(@NonNull StructNlMsgHdr nlmsghdr) { - mHeader = nlmsghdr; - } - - @NonNull - public StructNlMsgHdr getHeader() { - return mHeader; - } - - @Override - public String toString() { - // The netlink family is not provided to StructNlMsgHdr#toString because NetlinkMessage - // doesn't store the information. So the netlink message type can't be transformed into - // a string by StructNlMsgHdr#toString and just keep as an integer. The specific message - // which inherits NetlinkMessage could override NetlinkMessage#toString and provide the - // specific netlink family to StructNlMsgHdr#toString. - return "NetlinkMessage{" + mHeader.toString() + "}"; - } - - @NonNull - private static NetlinkMessage parseCtlMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer, int payloadLength) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.NLMSG_ERROR: - return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer); - default: { - // Other netlink control messages. Just parse the header for now, - // pretending the whole message was consumed. - byteBuffer.position(byteBuffer.position() + payloadLength); - return new NetlinkMessage(nlmsghdr); - } - } - } - - @Nullable - private static NetlinkMessage parseRtMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.RTM_NEWLINK: - case NetlinkConstants.RTM_DELLINK: - return (NetlinkMessage) RtNetlinkLinkMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWADDR: - case NetlinkConstants.RTM_DELADDR: - return (NetlinkMessage) RtNetlinkAddressMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWROUTE: - case NetlinkConstants.RTM_DELROUTE: - return (NetlinkMessage) RtNetlinkRouteMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWNEIGH: - case NetlinkConstants.RTM_DELNEIGH: - case NetlinkConstants.RTM_GETNEIGH: - return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.RTM_NEWNDUSEROPT: - return (NetlinkMessage) NduseroptMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } - - @Nullable - private static NetlinkMessage parseInetDiagMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.SOCK_DIAG_BY_FAMILY: - return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } - - @Nullable - private static NetlinkMessage parseNfMessage(@NonNull StructNlMsgHdr nlmsghdr, - @NonNull ByteBuffer byteBuffer) { - switch (nlmsghdr.nlmsg_type) { - case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 - | NetlinkConstants.IPCTNL_MSG_CT_NEW: - case NetlinkConstants.NFNL_SUBSYS_CTNETLINK << 8 - | NetlinkConstants.IPCTNL_MSG_CT_DELETE: - return (NetlinkMessage) ConntrackMessage.parse(nlmsghdr, byteBuffer); - default: return null; - } - } -} diff --git a/common/device/com/android/net/module/util/netlink/NetlinkUtils.java b/common/device/com/android/net/module/util/netlink/NetlinkUtils.java deleted file mode 100644 index 33bd36d8..00000000 --- a/common/device/com/android/net/module/util/netlink/NetlinkUtils.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.netlink; - -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; -import static android.system.OsConstants.AF_NETLINK; -import static android.system.OsConstants.EIO; -import static android.system.OsConstants.EPROTO; -import static android.system.OsConstants.ETIMEDOUT; -import static android.system.OsConstants.NETLINK_INET_DIAG; -import static android.system.OsConstants.NETLINK_ROUTE; -import static android.system.OsConstants.SOCK_CLOEXEC; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_RCVBUF; -import static android.system.OsConstants.SO_RCVTIMEO; -import static android.system.OsConstants.SO_SNDTIMEO; - -import android.net.util.SocketUtils; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructTimeval; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.Inet6Address; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * Utilities for netlink related class that may not be able to fit into a specific class. - * @hide - */ -public class NetlinkUtils { - private static final String TAG = "NetlinkUtils"; - /** Corresponds to enum from bionic/libc/include/netinet/tcp.h. */ - private static final int TCP_ESTABLISHED = 1; - private static final int TCP_SYN_SENT = 2; - private static final int TCP_SYN_RECV = 3; - - public static final int TCP_ALIVE_STATE_FILTER = - (1 << TCP_ESTABLISHED) | (1 << TCP_SYN_SENT) | (1 << TCP_SYN_RECV); - - public static final int UNKNOWN_MARK = 0xffffffff; - public static final int NULL_MASK = 0; - - // Initial mark value corresponds to the initValue in system/netd/include/Fwmark.h. - public static final int INIT_MARK_VALUE = 0; - // Corresponds to enum definition in bionic/libc/kernel/uapi/linux/inet_diag.h - public static final int INET_DIAG_INFO = 2; - public static final int INET_DIAG_MARK = 15; - - public static final long IO_TIMEOUT_MS = 300L; - - public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; - public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; - - /** - * Return whether the input ByteBuffer contains enough remaining bytes for - * {@code StructNlMsgHdr}. - */ - public static boolean enoughBytesRemainForValidNlMsg(@NonNull final ByteBuffer bytes) { - return bytes.remaining() >= StructNlMsgHdr.STRUCT_SIZE; - } - - /** - * Parse netlink error message - * - * @param bytes byteBuffer to parse netlink error message - * @return NetlinkErrorMessage if bytes contains valid NetlinkErrorMessage, else {@code null} - */ - @Nullable - private static NetlinkErrorMessage parseNetlinkErrorMessage(ByteBuffer bytes) { - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(bytes); - if (nlmsghdr == null || nlmsghdr.nlmsg_type != NetlinkConstants.NLMSG_ERROR) { - return null; - } - - final int messageLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - final int payloadLength = messageLength - StructNlMsgHdr.STRUCT_SIZE; - if (payloadLength < 0 || payloadLength > bytes.remaining()) { - // Malformed message or runt buffer. Pretend the buffer was consumed. - bytes.position(bytes.limit()); - return null; - } - - return NetlinkErrorMessage.parse(nlmsghdr, bytes); - } - - /** - * Receive netlink ack message and check error - * - * @param fd fd to read netlink message - */ - public static void receiveNetlinkAck(final FileDescriptor fd) - throws InterruptedIOException, ErrnoException { - final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT_MS); - // recvMessage() guaranteed to not return null if it did not throw. - final NetlinkErrorMessage response = parseNetlinkErrorMessage(bytes); - if (response != null && response.getNlMsgError() != null) { - final int errno = response.getNlMsgError().error; - if (errno != 0) { - // TODO: consider ignoring EINVAL (-22), which appears to be - // normal when probing a neighbor for which the kernel does - // not already have / no longer has a link layer address. - Log.e(TAG, "receiveNetlinkAck, errmsg=" + response.toString()); - // Note: convert kernel errnos (negative) into userspace errnos (positive). - throw new ErrnoException(response.toString(), Math.abs(errno)); - } - } else { - final String errmsg; - if (response == null) { - bytes.position(0); - errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); - } else { - errmsg = response.toString(); - } - Log.e(TAG, "receiveNetlinkAck, errmsg=" + errmsg); - throw new ErrnoException(errmsg, EPROTO); - } - } - - /** - * Send one netlink message to kernel via netlink socket. - * - * @param nlProto netlink protocol type. - * @param msg the raw bytes of netlink message to be sent. - */ - public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { - final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; - final FileDescriptor fd = netlinkSocketForProto(nlProto); - - try { - connectSocketToNetlink(fd); - sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT_MS); - receiveNetlinkAck(fd); - } catch (InterruptedIOException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, ETIMEDOUT, e); - } catch (SocketException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, EIO, e); - } finally { - try { - SocketUtils.closeSocket(fd); - } catch (IOException e) { - // Nothing we can do here - } - } - } - - /** - * Send an RTM_NEWADDR message to kernel to add or update an IPv6 address. - * - * @param ifIndex interface index. - * @param ip IPv6 address to be added. - * @param prefixlen IPv6 address prefix length. - * @param flags IPv6 address flags. - * @param scope IPv6 address scope. - * @param preferred The preferred lifetime of IPv6 address. - * @param valid The valid lifetime of IPv6 address. - */ - public static boolean sendRtmNewAddressRequest(int ifIndex, @NonNull final Inet6Address ip, - short prefixlen, int flags, byte scope, long preferred, long valid) { - Objects.requireNonNull(ip, "IPv6 address to be added should not be null."); - final byte[] msg = RtNetlinkAddressMessage.newRtmNewAddressMessage(1 /* seqNo*/, ip, - prefixlen, flags, scope, ifIndex, preferred, valid); - try { - NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - return true; - } catch (ErrnoException e) { - Log.e(TAG, "Fail to send RTM_NEWADDR to add " + ip.getHostAddress(), e); - return false; - } - } - - /** - * Send an RTM_DELADDR message to kernel to delete an IPv6 address. - * - * @param ifIndex interface index. - * @param ip IPv6 address to be deleted. - * @param prefixlen IPv6 address prefix length. - */ - public static boolean sendRtmDelAddressRequest(int ifIndex, final Inet6Address ip, - short prefixlen) { - Objects.requireNonNull(ip, "IPv6 address to be deleted should not be null."); - final byte[] msg = RtNetlinkAddressMessage.newRtmDelAddressMessage(1 /* seqNo*/, ip, - prefixlen, ifIndex); - try { - NetlinkUtils.sendOneShotKernelMessage(NETLINK_ROUTE, msg); - return true; - } catch (ErrnoException e) { - Log.e(TAG, "Fail to send RTM_DELADDR to delete " + ip.getHostAddress(), e); - return false; - } - } - - /** - * Create netlink socket with the given netlink protocol type. - * - * @return fd the fileDescriptor of the socket. - * @throws ErrnoException if the FileDescriptor not connect to be created successfully - */ - public static FileDescriptor netlinkSocketForProto(int nlProto) throws ErrnoException { - final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); - Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); - return fd; - } - - /** - * Construct a netlink inet_diag socket. - */ - public static FileDescriptor createNetLinkInetDiagSocket() throws ErrnoException { - return Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_INET_DIAG); - } - - /** - * Connect the given file descriptor to the Netlink interface to the kernel. - * - * The fd must be a SOCK_DGRAM socket : create it with {@link #netlinkSocketForProto} - * - * @throws ErrnoException if the {@code fd} could not connect to kernel successfully - * @throws SocketException if there is an error accessing a socket. - */ - public static void connectSocketToNetlink(FileDescriptor fd) - throws ErrnoException, SocketException { - Os.connect(fd, makeNetlinkSocketAddress(0, 0)); - } - - private static void checkTimeout(long timeoutMs) { - if (timeoutMs < 0) { - throw new IllegalArgumentException("Negative timeouts not permitted"); - } - } - - /** - * Wait up to |timeoutMs| (or until underlying socket error) for a - * netlink message of at most |bufsize| size. - * - * Multi-threaded calls with different timeouts will cause unexpected results. - */ - public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); - - final ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); - final int length = Os.read(fd, byteBuffer); - if (length == bufsize) { - Log.w(TAG, "maximum read"); - } - byteBuffer.position(0); - byteBuffer.limit(length); - byteBuffer.order(ByteOrder.nativeOrder()); - return byteBuffer; - } - - /** - * Send a message to a peer to which this socket has previously connected. - * - * This waits at most |timeoutMs| milliseconds for the send to complete, will get the exception - * if it times out. - */ - public static int sendMessage( - FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); - return Os.write(fd, bytes, offset, count); - } - - private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); - - /** - * Convert the system time in clock ticks(clock_t type in times(), not in clock()) to - * milliseconds. times() clock_t ticks at the kernel's USER_HZ (100) while clock() clock_t - * ticks at CLOCKS_PER_SEC (1000000). - * - * See the NOTES on https://man7.org/linux/man-pages/man2/times.2.html for the difference - * of clock_t used in clock() and times(). - */ - public static long ticksToMilliSeconds(int intClockTicks) { - final long longClockTicks = intClockTicks & 0xffffffffL; - return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; - } - - private NetlinkUtils() {} -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java deleted file mode 100644 index cbe0ab0e..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkAddressMessage.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import com.android.net.module.util.HexDump; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * A NetlinkMessage subclass for rtnetlink address messages. - * - * RtNetlinkAddressMessage.parse() must be called with a ByteBuffer that contains exactly one - * netlink message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkAddressMessage extends NetlinkMessage { - public static final short IFA_ADDRESS = 1; - public static final short IFA_CACHEINFO = 6; - public static final short IFA_FLAGS = 8; - - private int mFlags; - @NonNull - private StructIfaddrMsg mIfaddrmsg; - @NonNull - private InetAddress mIpAddress; - @Nullable - private StructIfacacheInfo mIfacacheInfo; - - @VisibleForTesting - public RtNetlinkAddressMessage(@NonNull final StructNlMsgHdr header, - @NonNull final StructIfaddrMsg ifaddrMsg, - @NonNull final InetAddress ipAddress, - @Nullable final StructIfacacheInfo structIfacacheInfo, - int flags) { - super(header); - mIfaddrmsg = ifaddrMsg; - mIpAddress = ipAddress; - mIfacacheInfo = structIfacacheInfo; - mFlags = flags; - } - private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { - this(header, null, null, null, 0); - } - - public int getFlags() { - return mFlags; - } - - @NonNull - public StructIfaddrMsg getIfaddrHeader() { - return mIfaddrmsg; - } - - @NonNull - public InetAddress getIpAddress() { - return mIpAddress; - } - - @Nullable - public StructIfacacheInfo getIfacacheInfo() { - return mIfacacheInfo; - } - - /** - * Parse rtnetlink address message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkAddressMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkAddressMessage addrMsg = new RtNetlinkAddressMessage(header); - - addrMsg.mIfaddrmsg = StructIfaddrMsg.parse(byteBuffer); - if (addrMsg.mIfaddrmsg == null) return null; - - // IFA_ADDRESS - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFA_ADDRESS, byteBuffer); - if (nlAttr == null) return null; - addrMsg.mIpAddress = nlAttr.getValueAsInetAddress(); - if (addrMsg.mIpAddress == null) return null; - - // IFA_CACHEINFO - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - addrMsg.mIfacacheInfo = StructIfacacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - // The first 8 bits of flags are in the ifaddrmsg. - addrMsg.mFlags = addrMsg.mIfaddrmsg.flags; - // IFA_FLAGS. All the flags are in the IF_FLAGS attribute. This should always be present, - // and will overwrite the flags set above. - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFA_FLAGS, byteBuffer); - if (nlAttr == null) return null; - final Integer value = nlAttr.getValueAsInteger(); - if (value == null) return null; - addrMsg.mFlags = value; - - return addrMsg; - } - - /** - * Write a rtnetlink address message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mIfaddrmsg.pack(byteBuffer); - - final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, mIpAddress); - address.pack(byteBuffer); - - if (mIfacacheInfo != null) { - final StructNlAttr cacheInfo = new StructNlAttr(IFA_CACHEINFO, - mIfacacheInfo.writeToBytes()); - cacheInfo.pack(byteBuffer); - } - - // If IFA_FLAGS attribute isn't present on the wire at parsing netlink message, it will - // still be packed to ByteBuffer even if the flag is 0. - final StructNlAttr flags = new StructNlAttr(IFA_FLAGS, mFlags); - flags.pack(byteBuffer); - } - - /** - * A convenience method to create a RTM_NEWADDR message. - */ - public static byte[] newRtmNewAddressMessage(int seqNo, @NonNull final InetAddress ip, - short prefixlen, int flags, byte scope, int ifIndex, long preferred, long valid) { - Objects.requireNonNull(ip, "IP address to be set via netlink message cannot be null"); - - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK; - nlmsghdr.nlmsg_seq = seqNo; - - final RtNetlinkAddressMessage msg = new RtNetlinkAddressMessage(nlmsghdr); - final byte family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - // IFA_FLAGS attribute is always present within this method, just set flags from - // ifaddrmsg to 0. kernel will prefer the flags from IFA_FLAGS attribute. - msg.mIfaddrmsg = - new StructIfaddrMsg(family, prefixlen, (short) 0 /* flags */, scope, ifIndex); - msg.mIpAddress = ip; - msg.mIfacacheInfo = new StructIfacacheInfo(preferred, valid, 0 /* cstamp */, - 0 /* tstamp */); - msg.mFlags = flags; - - final byte[] bytes = new byte[msg.getRequiredSpace()]; - nlmsghdr.nlmsg_len = bytes.length; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - msg.pack(byteBuffer); - return bytes; - } - - /** - * A convenience method to create a RTM_DELADDR message. - */ - public static byte[] newRtmDelAddressMessage(int seqNo, @NonNull final InetAddress ip, - short prefixlen, int ifIndex) { - Objects.requireNonNull(ip, "IP address to be deleted via netlink message cannot be null"); - - final int ifaAddrAttrLength = NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + ip.getAddress().length); - final int length = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE - + ifaAddrAttrLength; - final byte[] bytes = new byte[length]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_len = length; - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_DELADDR; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - nlmsghdr.nlmsg_seq = seqNo; - nlmsghdr.pack(byteBuffer); - - final byte family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - // Actually kernel ignores scope and flags(only deal with IFA_F_MANAGETEMPADDR, it - // indicates that all relevant IPv6 temporary addresses should be deleted as well when - // user space intends to delete a global IPv6 address with IFA_F_MANAGETEMPADDR), so - // far IFA_F_MANAGETEMPADDR flag isn't used in user space, it's fine to ignore it. - // However, we need to add IFA_FLAGS attribute in RTM_DELADDR if flags parsing should - // be supported in the future. - final StructIfaddrMsg ifaddrmsg = new StructIfaddrMsg(family, prefixlen, - (short) 0 /* flags */, (short) 0 /* scope */, ifIndex); - ifaddrmsg.pack(byteBuffer); - - final StructNlAttr address = new StructNlAttr(IFA_ADDRESS, ip); - address.pack(byteBuffer); - - return bytes; - } - - // This function helper gives the required buffer size for IFA_ADDRESS, IFA_CACHEINFO and - // IFA_FLAGS attributes encapsulation. However, that's not a mandatory requirement for all - // RtNetlinkAddressMessage, e.g. RTM_DELADDR sent from user space to kernel to delete an - // IP address only requires IFA_ADDRESS attribute. The caller should check if these attributes - // are necessary to carry when constructing a RtNetlinkAddressMessage. - private int getRequiredSpace() { - int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructIfaddrMsg.STRUCT_SIZE; - // IFA_ADDRESS attr - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mIpAddress.getAddress().length); - // IFA_CACHEINFO attr - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + StructIfacacheInfo.STRUCT_SIZE); - // IFA_FLAGS "u32" attr - spaceRequired += StructNlAttr.NLA_HEADERLEN + 4; - return spaceRequired; - } - - @Override - public String toString() { - return "RtNetlinkAddressMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Ifaddrmsg{" + mIfaddrmsg.toString() + "}, " - + "IP Address{" + mIpAddress.getHostAddress() + "}, " - + "IfacacheInfo{" + (mIfacacheInfo == null ? "" : mIfacacheInfo.toString()) + "}, " - + "Address Flags{" + HexDump.toHexString(mFlags) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java deleted file mode 100644 index 92ec0c4e..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkLinkMessage.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import android.net.MacAddress; -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for rtnetlink link messages. - * - * RtNetlinkLinkMessage.parse() must be called with a ByteBuffer that contains exactly one netlink - * message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkLinkMessage extends NetlinkMessage { - public static final short IFLA_ADDRESS = 1; - public static final short IFLA_IFNAME = 3; - public static final short IFLA_MTU = 4; - - private int mMtu; - @NonNull - private StructIfinfoMsg mIfinfomsg; - @Nullable - private MacAddress mHardwareAddress; - @Nullable - private String mInterfaceName; - - private RtNetlinkLinkMessage(@NonNull StructNlMsgHdr header) { - super(header); - mIfinfomsg = null; - mMtu = 0; - mHardwareAddress = null; - mInterfaceName = null; - } - - public int getMtu() { - return mMtu; - } - - @NonNull - public StructIfinfoMsg getIfinfoHeader() { - return mIfinfomsg; - } - - @Nullable - public MacAddress getHardwareAddress() { - return mHardwareAddress; - } - - @Nullable - public String getInterfaceName() { - return mInterfaceName; - } - - /** - * Parse rtnetlink link message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkLinkMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkLinkMessage linkMsg = new RtNetlinkLinkMessage(header); - - linkMsg.mIfinfomsg = StructIfinfoMsg.parse(byteBuffer); - if (linkMsg.mIfinfomsg == null) return null; - - // IFLA_MTU - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(IFLA_MTU, byteBuffer); - if (nlAttr != null) { - linkMsg.mMtu = nlAttr.getValueAsInt(0 /* default value */); - } - - // IFLA_ADDRESS - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFLA_ADDRESS, byteBuffer); - if (nlAttr != null) { - linkMsg.mHardwareAddress = nlAttr.getValueAsMacAddress(); - } - - // IFLA_IFNAME - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(IFLA_IFNAME, byteBuffer); - if (nlAttr != null) { - linkMsg.mInterfaceName = nlAttr.getValueAsString(); - } - - return linkMsg; - } - - /** - * Write a rtnetlink link message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mIfinfomsg.pack(byteBuffer); - - if (mMtu != 0) { - final StructNlAttr mtu = new StructNlAttr(IFLA_MTU, mMtu); - mtu.pack(byteBuffer); - } - if (mHardwareAddress != null) { - final StructNlAttr hardwareAddress = new StructNlAttr(IFLA_ADDRESS, mHardwareAddress); - hardwareAddress.pack(byteBuffer); - } - if (mInterfaceName != null) { - final StructNlAttr ifname = new StructNlAttr(IFLA_IFNAME, mInterfaceName); - ifname.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "RtNetlinkLinkMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Ifinfomsg{" + mIfinfomsg.toString() + "}, " - + "Hardware Address{" + mHardwareAddress + "}, " - + "MTU{" + mMtu + "}, " - + "Ifname{" + mInterfaceName + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java deleted file mode 100644 index 4a090151..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkNeighborMessage.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A NetlinkMessage subclass for rtnetlink neighbor messages. - * - * see also: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class RtNetlinkNeighborMessage extends NetlinkMessage { - public static final short NDA_UNSPEC = 0; - public static final short NDA_DST = 1; - public static final short NDA_LLADDR = 2; - public static final short NDA_CACHEINFO = 3; - public static final short NDA_PROBES = 4; - public static final short NDA_VLAN = 5; - public static final short NDA_PORT = 6; - public static final short NDA_VNI = 7; - public static final short NDA_IFINDEX = 8; - public static final short NDA_MASTER = 9; - - /** - * Parse routing socket netlink neighbor message from ByteBuffer. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @Nullable - public static RtNetlinkNeighborMessage parse(@NonNull StructNlMsgHdr header, - @NonNull ByteBuffer byteBuffer) { - final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header); - - neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer); - if (neighMsg.mNdmsg == null) { - return null; - } - - // Some of these are message-type dependent, and not always present. - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(NDA_DST, byteBuffer); - if (nlAttr != null) { - neighMsg.mDestination = nlAttr.getValueAsInetAddress(); - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(NDA_LLADDR, byteBuffer); - if (nlAttr != null) { - neighMsg.mLinkLayerAddr = nlAttr.nla_value; - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(NDA_PROBES, byteBuffer); - if (nlAttr != null) { - neighMsg.mNumProbes = nlAttr.getValueAsInt(0); - } - - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(NDA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( - neighMsg.mHeader.nlmsg_len - kMinConsumed); - if (byteBuffer.remaining() < kAdditionalSpace) { - byteBuffer.position(byteBuffer.limit()); - } else { - byteBuffer.position(baseOffset + kAdditionalSpace); - } - - return neighMsg; - } - - /** - * A convenience method to create an RTM_GETNEIGH request message. - */ - public static byte[] newGetNeighborsRequest(int seqNo) { - final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - final byte[] bytes = new byte[length]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_len = length; - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - nlmsghdr.nlmsg_seq = seqNo; - nlmsghdr.pack(byteBuffer); - - final StructNdMsg ndmsg = new StructNdMsg(); - ndmsg.pack(byteBuffer); - - return bytes; - } - - /** - * A convenience method to create an RTM_NEWNEIGH message, to modify - * the kernel's state information for a specific neighbor. - */ - public static byte[] newNewNeighborMessage( - int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) { - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; - nlmsghdr.nlmsg_seq = seqNo; - - final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr); - msg.mNdmsg = new StructNdMsg(); - msg.mNdmsg.ndm_family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - msg.mNdmsg.ndm_ifindex = ifIndex; - msg.mNdmsg.ndm_state = nudState; - msg.mDestination = ip; - msg.mLinkLayerAddr = llAddr; // might be null - - final byte[] bytes = new byte[msg.getRequiredSpace()]; - nlmsghdr.nlmsg_len = bytes.length; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - msg.pack(byteBuffer); - return bytes; - } - - private StructNdMsg mNdmsg; - private InetAddress mDestination; - private byte[] mLinkLayerAddr; - private int mNumProbes; - private StructNdaCacheInfo mCacheInfo; - - private RtNetlinkNeighborMessage(@NonNull StructNlMsgHdr header) { - super(header); - mNdmsg = null; - mDestination = null; - mLinkLayerAddr = null; - mNumProbes = 0; - mCacheInfo = null; - } - - public StructNdMsg getNdHeader() { - return mNdmsg; - } - - public InetAddress getDestination() { - return mDestination; - } - - public byte[] getLinkLayerAddress() { - return mLinkLayerAddr; - } - - public int getProbes() { - return mNumProbes; - } - - public StructNdaCacheInfo getCacheInfo() { - return mCacheInfo; - } - - private int getRequiredSpace() { - int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - if (mDestination != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length); - } - if (mLinkLayerAddr != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length); - } - // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO - // attributes appended. Fix later, if necessary. - return spaceRequired; - } - - private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) { - final StructNlAttr nlAttr = new StructNlAttr(); - nlAttr.nla_type = nlType; - nlAttr.nla_value = nlValue; - nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length); - nlAttr.pack(byteBuffer); - } - - /** - * Write a neighbor discovery netlink message to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mNdmsg.pack(byteBuffer); - - if (mDestination != null) { - packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer); - } - if (mLinkLayerAddr != null) { - packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer); - } - } - - @Override - public String toString() { - final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); - return "RtNetlinkNeighborMessage{ " - + "nlmsghdr{" - + (mHeader == null ? "" : mHeader.toString(OsConstants.NETLINK_ROUTE)) + "}, " - + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " - + "destination{" + ipLiteral + "} " - + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " - + "probes{" + mNumProbes + "} " - + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java b/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java deleted file mode 100644 index 9acac69c..00000000 --- a/common/device/com/android/net/module/util/netlink/RtNetlinkRouteMessage.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; - -import android.annotation.SuppressLint; -import android.net.IpPrefix; -import android.system.OsConstants; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.VisibleForTesting; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; - -/** - * A NetlinkMessage subclass for rtnetlink route messages. - * - * RtNetlinkRouteMessage.parse() must be called with a ByteBuffer that contains exactly one - * netlink message. - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class RtNetlinkRouteMessage extends NetlinkMessage { - public static final short RTA_DST = 1; - public static final short RTA_OIF = 4; - public static final short RTA_GATEWAY = 5; - public static final short RTA_CACHEINFO = 12; - - private int mIfindex; - @NonNull - private StructRtMsg mRtmsg; - @NonNull - private IpPrefix mDestination; - @Nullable - private InetAddress mGateway; - @Nullable - private StructRtaCacheInfo mRtaCacheInfo; - - private RtNetlinkRouteMessage(StructNlMsgHdr header) { - super(header); - mRtmsg = null; - mDestination = null; - mGateway = null; - mIfindex = 0; - mRtaCacheInfo = null; - } - - public int getInterfaceIndex() { - return mIfindex; - } - - @NonNull - public StructRtMsg getRtMsgHeader() { - return mRtmsg; - } - - @NonNull - public IpPrefix getDestination() { - return mDestination; - } - - @Nullable - public InetAddress getGateway() { - return mGateway; - } - - @Nullable - public StructRtaCacheInfo getRtaCacheInfo() { - return mRtaCacheInfo; - } - - /** - * Check whether the address families of destination and gateway match rtm_family in - * StructRtmsg. - * - * For example, IPv4-mapped IPv6 addresses as an IPv6 address will be always converted to IPv4 - * address, that's incorrect when upper layer creates a new {@link RouteInfo} class instance - * for IPv6 route with the converted IPv4 gateway. - */ - private static boolean matchRouteAddressFamily(@NonNull final InetAddress address, - int family) { - return ((address instanceof Inet4Address) && (family == AF_INET)) - || ((address instanceof Inet6Address) && (family == AF_INET6)); - } - - /** - * Parse rtnetlink route message from {@link ByteBuffer}. This method must be called with a - * ByteBuffer that contains exactly one netlink message. - * - * @param header netlink message header. - * @param byteBuffer the ByteBuffer instance that wraps the raw netlink message bytes. - */ - @SuppressLint("NewApi") - @Nullable - public static RtNetlinkRouteMessage parse(@NonNull final StructNlMsgHdr header, - @NonNull final ByteBuffer byteBuffer) { - final RtNetlinkRouteMessage routeMsg = new RtNetlinkRouteMessage(header); - - routeMsg.mRtmsg = StructRtMsg.parse(byteBuffer); - if (routeMsg.mRtmsg == null) return null; - int rtmFamily = routeMsg.mRtmsg.family; - - // RTA_DST - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = StructNlAttr.findNextAttrOfType(RTA_DST, byteBuffer); - if (nlAttr != null) { - final InetAddress destination = nlAttr.getValueAsInetAddress(); - // If the RTA_DST attribute is malformed, return null. - if (destination == null) return null; - // If the address family of destination doesn't match rtm_family, return null. - if (!matchRouteAddressFamily(destination, rtmFamily)) return null; - routeMsg.mDestination = new IpPrefix(destination, routeMsg.mRtmsg.dstLen); - } else if (rtmFamily == AF_INET) { - routeMsg.mDestination = new IpPrefix(IPV4_ADDR_ANY, 0); - } else if (rtmFamily == AF_INET6) { - routeMsg.mDestination = new IpPrefix(IPV6_ADDR_ANY, 0); - } else { - return null; - } - - // RTA_GATEWAY - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_GATEWAY, byteBuffer); - if (nlAttr != null) { - routeMsg.mGateway = nlAttr.getValueAsInetAddress(); - // If the RTA_GATEWAY attribute is malformed, return null. - if (routeMsg.mGateway == null) return null; - // If the address family of gateway doesn't match rtm_family, return null. - if (!matchRouteAddressFamily(routeMsg.mGateway, rtmFamily)) return null; - } - - // RTA_OIF - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_OIF, byteBuffer); - if (nlAttr != null) { - // Any callers that deal with interface names are responsible for converting - // the interface index to a name themselves. This may not succeed or may be - // incorrect, because the interface might have been deleted, or even deleted - // and re-added with a different index, since the netlink message was sent. - routeMsg.mIfindex = nlAttr.getValueAsInt(0 /* 0 isn't a valid ifindex */); - } - - // RTA_CACHEINFO - byteBuffer.position(baseOffset); - nlAttr = StructNlAttr.findNextAttrOfType(RTA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - routeMsg.mRtaCacheInfo = StructRtaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - return routeMsg; - } - - /** - * Write a rtnetlink address message to {@link ByteBuffer}. - */ - @VisibleForTesting - protected void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer); - mRtmsg.pack(byteBuffer); - - final StructNlAttr destination = new StructNlAttr(RTA_DST, mDestination.getAddress()); - destination.pack(byteBuffer); - - if (mGateway != null) { - final StructNlAttr gateway = new StructNlAttr(RTA_GATEWAY, mGateway.getAddress()); - gateway.pack(byteBuffer); - } - if (mIfindex != 0) { - final StructNlAttr ifindex = new StructNlAttr(RTA_OIF, mIfindex); - ifindex.pack(byteBuffer); - } - if (mRtaCacheInfo != null) { - final StructNlAttr cacheInfo = new StructNlAttr(RTA_CACHEINFO, - mRtaCacheInfo.writeToBytes()); - cacheInfo.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "RtNetlinkRouteMessage{ " - + "nlmsghdr{" + mHeader.toString(OsConstants.NETLINK_ROUTE) + "}, " - + "Rtmsg{" + mRtmsg.toString() + "}, " - + "destination{" + mDestination.getAddress().getHostAddress() + "}, " - + "gateway{" + (mGateway == null ? "" : mGateway.getHostAddress()) + "}, " - + "ifindex{" + mIfindex + "}, " - + "rta_cacheinfo{" + (mRtaCacheInfo == null ? "" : mRtaCacheInfo.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java b/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java deleted file mode 100644 index 360f56d2..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfacacheInfo.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifa_cacheinfo - * - * see also: - * - * include/uapi/linux/if_addr.h - * - * @hide - */ -public class StructIfacacheInfo extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - @Field(order = 0, type = Type.U32) - public final long preferred; - @Field(order = 1, type = Type.U32) - public final long valid; - @Field(order = 2, type = Type.U32) - public final long cstamp; // created timestamp, hundredths of seconds. - @Field(order = 3, type = Type.U32) - public final long tstamp; // updated timestamp, hundredths of seconds. - - StructIfacacheInfo(long preferred, long valid, long cstamp, long tstamp) { - this.preferred = preferred; - this.valid = valid; - this.cstamp = cstamp; - this.tstamp = tstamp; - } - - /** - * Parse an ifa_cacheinfo struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifa_cacheinfo. - * @return the parsed ifa_cacheinfo struct, or {@code null} if the ifa_cacheinfo struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfacacheInfo parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfacacheInfo.class, byteBuffer); - } - - /** - * Write an ifa_cacheinfo struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java b/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java deleted file mode 100644 index f9781a7b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfaddrMsg.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifaddrmsg - * - * see also: - * - * include/uapi/linux/if_addr.h - * - * @hide - */ -public class StructIfaddrMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 8; - - @Field(order = 0, type = Type.U8) - public final short family; - @Field(order = 1, type = Type.U8) - public final short prefixLen; - @Field(order = 2, type = Type.U8) - public final short flags; - @Field(order = 3, type = Type.U8) - public final short scope; - @Field(order = 4, type = Type.S32) - public final int index; - - public StructIfaddrMsg(short family, short prefixLen, short flags, short scope, int index) { - this.family = family; - this.prefixLen = prefixLen; - this.flags = flags; - this.scope = scope; - this.index = index; - } - - /** - * Parse an ifaddrmsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifaddrmsg. - * @return the parsed ifaddrmsg struct, or {@code null} if the ifaddrmsg struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfaddrMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfaddrMsg.class, byteBuffer); - } - - /** - * Write an ifaddrmsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java b/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java deleted file mode 100644 index 02d1574b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructIfinfoMsg.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct ifinfomsg - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructIfinfoMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - @Field(order = 0, type = Type.U8, padding = 1) - public final short family; - @Field(order = 1, type = Type.U16) - public final int type; - @Field(order = 2, type = Type.S32) - public final int index; - @Field(order = 3, type = Type.U32) - public final long flags; - @Field(order = 4, type = Type.U32) - public final long change; - - StructIfinfoMsg(short family, int type, int index, long flags, long change) { - this.family = family; - this.type = type; - this.index = index; - this.flags = flags; - this.change = change; - } - - /** - * Parse an ifinfomsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the ifinfomsg. - * @return the parsed ifinfomsg struct, or {@code null} if the ifinfomsg struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructIfinfoMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructIfinfoMsg.class, byteBuffer); - } - - /** - * Write an ifinfomsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java b/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java deleted file mode 100644 index cbd895d6..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagMsg.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * struct inet_diag_msg - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_msg { - * __u8 idiag_family; - * __u8 idiag_state; - * __u8 idiag_timer; - * __u8 idiag_retrans; - * struct inet_diag_sockid id; - * __u32 idiag_expires; - * __u32 idiag_rqueue; - * __u32 idiag_wqueue; - * __u32 idiag_uid; - * __u32 idiag_inode; - * }; - * - * @hide - */ -public class StructInetDiagMsg { - public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; - public short idiag_family; - public short idiag_state; - public short idiag_timer; - public short idiag_retrans; - @NonNull - public StructInetDiagSockId id; - public long idiag_expires; - public long idiag_rqueue; - public long idiag_wqueue; - // Use int for uid since other code use int for uid and uid fits to int - public int idiag_uid; - public long idiag_inode; - - private static short unsignedByte(byte b) { - return (short) (b & 0xFF); - } - - /** - * Parse inet diag netlink message from buffer. - */ - @Nullable - public static StructInetDiagMsg parse(@NonNull ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) { - return null; - } - StructInetDiagMsg struct = new StructInetDiagMsg(); - struct.idiag_family = unsignedByte(byteBuffer.get()); - struct.idiag_state = unsignedByte(byteBuffer.get()); - struct.idiag_timer = unsignedByte(byteBuffer.get()); - struct.idiag_retrans = unsignedByte(byteBuffer.get()); - struct.id = StructInetDiagSockId.parse(byteBuffer, struct.idiag_family); - if (struct.id == null) { - return null; - } - struct.idiag_expires = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_rqueue = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_wqueue = Integer.toUnsignedLong(byteBuffer.getInt()); - struct.idiag_uid = byteBuffer.getInt(); - struct.idiag_inode = Integer.toUnsignedLong(byteBuffer.getInt()); - return struct; - } - - @Override - public String toString() { - return "StructInetDiagMsg{ " - + "idiag_family{" + idiag_family + "}, " - + "idiag_state{" + idiag_state + "}, " - + "idiag_timer{" + idiag_timer + "}, " - + "idiag_retrans{" + idiag_retrans + "}, " - + "id{" + id + "}, " - + "idiag_expires{" + idiag_expires + "}, " - + "idiag_rqueue{" + idiag_rqueue + "}, " - + "idiag_wqueue{" + idiag_wqueue + "}, " - + "idiag_uid{" + idiag_uid + "}, " - + "idiag_inode{" + idiag_inode + "}, " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java b/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java deleted file mode 100644 index 3b47008a..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagReqV2.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * struct inet_diag_req_v2 - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_req_v2 { - * __u8 sdiag_family; - * __u8 sdiag_protocol; - * __u8 idiag_ext; - * __u8 pad; - * __u32 idiag_states; - * struct inet_diag_sockid id; - * }; - * - * @hide - */ -public class StructInetDiagReqV2 { - public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE; - - private final byte mSdiagFamily; - private final byte mSdiagProtocol; - private final byte mIdiagExt; - private final byte mPad; - private final StructInetDiagSockId mId; - private final int mState; - public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff; - - public StructInetDiagReqV2(int protocol, @Nullable StructInetDiagSockId id, int family, int pad, - int extension, int state) { - mSdiagFamily = (byte) family; - mSdiagProtocol = (byte) protocol; - mId = id; - mPad = (byte) pad; - mIdiagExt = (byte) extension; - mState = state; - } - - /** - * Write the int diag request v2 message to ByteBuffer. - */ - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. - byteBuffer.put((byte) mSdiagFamily); - byteBuffer.put((byte) mSdiagProtocol); - byteBuffer.put((byte) mIdiagExt); - byteBuffer.put((byte) mPad); - byteBuffer.putInt(mState); - if (mId != null) mId.pack(byteBuffer); - } - - @Override - public String toString() { - final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily); - final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol); - - return "StructInetDiagReqV2{ " - + "sdiag_family{" + familyStr + "}, " - + "sdiag_protocol{" + protocolStr + "}, " - + "idiag_ext{" + mIdiagExt + ")}, " - + "pad{" + mPad + "}, " - + "idiag_states{" + Integer.toHexString(mState) + "}, " - + ((mId != null) ? mId.toString() : "inet_diag_sockid=null") - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java b/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java deleted file mode 100644 index dd85934c..00000000 --- a/common/device/com/android/net/module/util/netlink/StructInetDiagSockId.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 com.android.net.module.util.netlink; - -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import android.util.Log; - -import androidx.annotation.Nullable; - -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * struct inet_diag_req_v2 - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_sockid { - * __be16 idiag_sport; - * __be16 idiag_dport; - * __be32 idiag_src[4]; - * __be32 idiag_dst[4]; - * __u32 idiag_if; - * __u32 idiag_cookie[2]; - * #define INET_DIAG_NOCOOKIE (~0U) - * }; - * - * @hide - */ -public class StructInetDiagSockId { - private static final String TAG = StructInetDiagSockId.class.getSimpleName(); - public static final int STRUCT_SIZE = 48; - - private static final long INET_DIAG_NOCOOKIE = ~0L; - private static final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - public final InetSocketAddress locSocketAddress; - public final InetSocketAddress remSocketAddress; - public final int ifIndex; - public final long cookie; - - public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) { - this(loc, rem, 0 /* ifIndex */, INET_DIAG_NOCOOKIE); - } - - public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem, - int ifIndex, long cookie) { - this.locSocketAddress = loc; - this.remSocketAddress = rem; - this.ifIndex = ifIndex; - this.cookie = cookie; - } - - /** - * Parse inet diag socket id from buffer. - */ - @Nullable - public static StructInetDiagSockId parse(final ByteBuffer byteBuffer, final short family) { - if (byteBuffer.remaining() < STRUCT_SIZE) { - return null; - } - - byteBuffer.order(BIG_ENDIAN); - final int srcPort = Short.toUnsignedInt(byteBuffer.getShort()); - final int dstPort = Short.toUnsignedInt(byteBuffer.getShort()); - - final InetAddress srcAddr; - final InetAddress dstAddr; - if (family == AF_INET) { - final byte[] srcAddrByte = new byte[IPV4_ADDR_LEN]; - final byte[] dstAddrByte = new byte[IPV4_ADDR_LEN]; - byteBuffer.get(srcAddrByte); - // Address always uses IPV6_ADDR_LEN in the buffer. So if the address is IPv4, position - // needs to be advanced to the next field. - byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); - byteBuffer.get(dstAddrByte); - byteBuffer.position(byteBuffer.position() + (IPV6_ADDR_LEN - IPV4_ADDR_LEN)); - try { - srcAddr = Inet4Address.getByAddress(srcAddrByte); - dstAddr = Inet4Address.getByAddress(dstAddrByte); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Failed to parse address: " + e); - return null; - } - } else if (family == AF_INET6) { - final byte[] srcAddrByte = new byte[IPV6_ADDR_LEN]; - final byte[] dstAddrByte = new byte[IPV6_ADDR_LEN]; - byteBuffer.get(srcAddrByte); - byteBuffer.get(dstAddrByte); - try { - // Using Inet6Address.getByAddress to be consistent with idiag_family field since - // InetAddress.getByAddress returns Inet4Address if the address is v4-mapped v6 - // address. - srcAddr = Inet6Address.getByAddress( - null /* host */, srcAddrByte, -1 /* scope_id */); - dstAddr = Inet6Address.getByAddress( - null /* host */, dstAddrByte, -1 /* scope_id */); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Failed to parse address: " + e); - return null; - } - } else { - Log.wtf(TAG, "Invalid address family: " + family); - return null; - } - - final InetSocketAddress srcSocketAddr = new InetSocketAddress(srcAddr, srcPort); - final InetSocketAddress dstSocketAddr = new InetSocketAddress(dstAddr, dstPort); - - byteBuffer.order(ByteOrder.nativeOrder()); - final int ifIndex = byteBuffer.getInt(); - final long cookie = byteBuffer.getLong(); - return new StructInetDiagSockId(srcSocketAddr, dstSocketAddr, ifIndex, cookie); - } - - /** - * Write inet diag socket id message to ByteBuffer in big endian. - */ - public void pack(ByteBuffer byteBuffer) { - byteBuffer.order(BIG_ENDIAN); - byteBuffer.putShort((short) locSocketAddress.getPort()); - byteBuffer.putShort((short) remSocketAddress.getPort()); - byteBuffer.put(locSocketAddress.getAddress().getAddress()); - if (locSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.put(remSocketAddress.getAddress().getAddress()); - if (remSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.order(ByteOrder.nativeOrder()); - byteBuffer.putInt(ifIndex); - byteBuffer.putLong(cookie); - } - - @Override - public String toString() { - return "StructInetDiagSockId{ " - + "idiag_sport{" + locSocketAddress.getPort() + "}, " - + "idiag_dport{" + remSocketAddress.getPort() + "}, " - + "idiag_src{" + locSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_dst{" + remSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_if{" + ifIndex + "}, " - + "idiag_cookie{" - + (cookie == INET_DIAG_NOCOOKIE ? "INET_DIAG_NOCOOKIE" : cookie) + "}" - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdMsg.java b/common/device/com/android/net/module/util/netlink/StructNdMsg.java deleted file mode 100644 index 53ce8991..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdMsg.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import android.system.OsConstants; - -import java.nio.ByteBuffer; - -/** - * struct ndmsg - * - * see: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class StructNdMsg { - // Already aligned. - public static final int STRUCT_SIZE = 12; - - // Neighbor Cache Entry States - public static final short NUD_NONE = 0x00; - public static final short NUD_INCOMPLETE = 0x01; - public static final short NUD_REACHABLE = 0x02; - public static final short NUD_STALE = 0x04; - public static final short NUD_DELAY = 0x08; - public static final short NUD_PROBE = 0x10; - public static final short NUD_FAILED = 0x20; - public static final short NUD_NOARP = 0x40; - public static final short NUD_PERMANENT = 0x80; - - /** - * Convert neighbor cache entry state integer to string. - */ - public static String stringForNudState(short nudState) { - switch (nudState) { - case NUD_NONE: return "NUD_NONE"; - case NUD_INCOMPLETE: return "NUD_INCOMPLETE"; - case NUD_REACHABLE: return "NUD_REACHABLE"; - case NUD_STALE: return "NUD_STALE"; - case NUD_DELAY: return "NUD_DELAY"; - case NUD_PROBE: return "NUD_PROBE"; - case NUD_FAILED: return "NUD_FAILED"; - case NUD_NOARP: return "NUD_NOARP"; - case NUD_PERMANENT: return "NUD_PERMANENT"; - default: - return "unknown NUD state: " + String.valueOf(nudState); - } - } - - /** - * Check whether a neighbor is connected or not. - */ - public static boolean isNudStateConnected(short nudState) { - return ((nudState & (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)) != 0); - } - - /** - * Check whether a neighbor is in the valid NUD state or not. - */ - public static boolean isNudStateValid(short nudState) { - return (isNudStateConnected(nudState) - || ((nudState & (NUD_PROBE | NUD_STALE | NUD_DELAY)) != 0)); - } - - // Neighbor Cache Entry Flags - public static byte NTF_USE = (byte) 0x01; - public static byte NTF_SELF = (byte) 0x02; - public static byte NTF_MASTER = (byte) 0x04; - public static byte NTF_PROXY = (byte) 0x08; - public static byte NTF_ROUTER = (byte) 0x80; - - private static String stringForNudFlags(byte flags) { - final StringBuilder sb = new StringBuilder(); - if ((flags & NTF_USE) != 0) { - sb.append("NTF_USE"); - } - if ((flags & NTF_SELF) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NTF_SELF"); - } - if ((flags & NTF_MASTER) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NTF_MASTER"); - } - if ((flags & NTF_PROXY) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NTF_PROXY"); - } - if ((flags & NTF_ROUTER) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NTF_ROUTER"); - } - return sb.toString(); - } - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse a neighbor discovery netlink message header from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the nd netlink message header. - * @return the parsed nd netlink message header, or {@code null} if the nd netlink message - * header could not be parsed successfully (for example, if it was truncated). - */ - public static StructNdMsg parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) return null; - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - final StructNdMsg struct = new StructNdMsg(); - struct.ndm_family = byteBuffer.get(); - final byte pad1 = byteBuffer.get(); - final short pad2 = byteBuffer.getShort(); - struct.ndm_ifindex = byteBuffer.getInt(); - struct.ndm_state = byteBuffer.getShort(); - struct.ndm_flags = byteBuffer.get(); - struct.ndm_type = byteBuffer.get(); - return struct; - } - - public byte ndm_family; - public int ndm_ifindex; - public short ndm_state; - public byte ndm_flags; - public byte ndm_type; - - public StructNdMsg() { - ndm_family = (byte) OsConstants.AF_UNSPEC; - } - - /** - * Write the neighbor discovery message header to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - byteBuffer.put(ndm_family); - byteBuffer.put((byte) 0); // pad1 - byteBuffer.putShort((short) 0); // pad2 - byteBuffer.putInt(ndm_ifindex); - byteBuffer.putShort(ndm_state); - byteBuffer.put(ndm_flags); - byteBuffer.put(ndm_type); - } - - /** - * Check whether a neighbor is connected or not. - */ - public boolean nudConnected() { - return isNudStateConnected(ndm_state); - } - - /** - * Check whether a neighbor is in the valid NUD state or not. - */ - public boolean nudValid() { - return isNudStateValid(ndm_state); - } - - @Override - public String toString() { - final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")"; - final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")"; - return "StructNdMsg{ " - + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, " - + "ifindex{" + ndm_ifindex + "}, " - + "state{" + stateStr + "}, " - + "flags{" + flagsStr + "}, " - + "type{" + ndm_type + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java b/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java deleted file mode 100644 index 82263466..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdOptPref64.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.net.module.util.netlink; - -import android.annotation.SuppressLint; -import android.net.IpPrefix; -import android.util.Log; - -import androidx.annotation.NonNull; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.util.Objects; - -/** - * The PREF64 router advertisement option. RFC 8781. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Scaled Lifetime | PLC | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | Highest 96 bits of the Prefix | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -public class StructNdOptPref64 extends NdOption { - public static final int STRUCT_SIZE = 16; - public static final int TYPE = 38; - public static final byte LENGTH = 2; - - private static final String TAG = StructNdOptPref64.class.getSimpleName(); - - /** - * How many seconds the prefix is expected to remain valid. - * Valid values are from 0 to 65528 in multiples of 8. - */ - public final int lifetime; - /** The NAT64 prefix. */ - @NonNull public final IpPrefix prefix; - - static int plcToPrefixLength(int plc) { - switch (plc) { - case 0: return 96; - case 1: return 64; - case 2: return 56; - case 3: return 48; - case 4: return 40; - case 5: return 32; - default: - throw new IllegalArgumentException("Invalid prefix length code " + plc); - } - } - - static int prefixLengthToPlc(int prefixLength) { - switch (prefixLength) { - case 96: return 0; - case 64: return 1; - case 56: return 2; - case 48: return 3; - case 40: return 4; - case 32: return 5; - default: - throw new IllegalArgumentException("Invalid prefix length " + prefixLength); - } - } - - /** - * Returns the 2-byte "scaled lifetime and prefix length code" field: 13-bit lifetime, 3-bit PLC - */ - static short getScaledLifetimePlc(int lifetime, int prefixLengthCode) { - return (short) ((lifetime & 0xfff8) | (prefixLengthCode & 0x7)); - } - - public StructNdOptPref64(@NonNull IpPrefix prefix, int lifetime) { - super((byte) TYPE, LENGTH); - - Objects.requireNonNull(prefix, "prefix must not be null"); - if (!(prefix.getAddress() instanceof Inet6Address)) { - throw new IllegalArgumentException("Must be an IPv6 prefix: " + prefix); - } - prefixLengthToPlc(prefix.getPrefixLength()); // Throw if the prefix length is invalid. - this.prefix = prefix; - - if (lifetime < 0 || lifetime > 0xfff8) { - throw new IllegalArgumentException("Invalid lifetime " + lifetime); - } - this.lifetime = lifetime & 0xfff8; - } - - @SuppressLint("NewApi") - private StructNdOptPref64(@NonNull ByteBuffer buf) { - super(buf.get(), Byte.toUnsignedInt(buf.get())); - if (type != TYPE) throw new IllegalArgumentException("Invalid type " + type); - if (length != LENGTH) throw new IllegalArgumentException("Invalid length " + length); - - int scaledLifetimePlc = Short.toUnsignedInt(buf.getShort()); - lifetime = scaledLifetimePlc & 0xfff8; - - byte[] addressBytes = new byte[16]; - buf.get(addressBytes, 0, 12); - InetAddress addr; - try { - addr = InetAddress.getByAddress(addressBytes); - } catch (UnknownHostException e) { - throw new AssertionError("16-byte array not valid InetAddress?"); - } - prefix = new IpPrefix(addr, plcToPrefixLength(scaledLifetimePlc & 7)); - } - - /** - * Parses an option from a {@link ByteBuffer}. - * - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully - * (for example, if it was truncated, or if the prefix length code was wrong). - */ - public static StructNdOptPref64 parse(@NonNull ByteBuffer buf) { - if (buf.remaining() < STRUCT_SIZE) return null; - try { - return new StructNdOptPref64(buf); - } catch (IllegalArgumentException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated, so - // callers must already handle it. - Log.d(TAG, "Invalid PREF64 option: " + e); - return null; - } - } - - protected void writeToByteBuffer(ByteBuffer buf) { - super.writeToByteBuffer(buf); - buf.putShort(getScaledLifetimePlc(lifetime, prefixLengthToPlc(prefix.getPrefixLength()))); - buf.put(prefix.getRawAddress(), 0, 12); - } - - /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ - public ByteBuffer toByteBuffer() { - ByteBuffer buf = ByteBuffer.allocate(STRUCT_SIZE); - writeToByteBuffer(buf); - buf.flip(); - return buf; - } - - @Override - @NonNull - public String toString() { - return String.format("NdOptPref64(%s, %d)", prefix, lifetime); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java b/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java deleted file mode 100644 index 6dee0c49..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdOptRdnss.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; - -import android.util.Log; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.structs.RdnssOption; - -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.Objects; -import java.util.StringJoiner; - -/** - * The Recursive DNS Server Option. RFC 8106. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * : Addresses of IPv6 Recursive DNS Servers : - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class StructNdOptRdnss extends NdOption { - private static final String TAG = StructNdOptRdnss.class.getSimpleName(); - public static final int TYPE = 25; - // Length in 8-byte units, only if one IPv6 address included. - public static final byte MIN_OPTION_LEN = 3; - - public final RdnssOption header; - @NonNull - public final Inet6Address[] servers; - - public StructNdOptRdnss(@NonNull final Inet6Address[] servers, long lifetime) { - super((byte) TYPE, servers.length * 2 + 1); - - Objects.requireNonNull(servers, "Recursive DNS Servers address array must not be null"); - if (servers.length == 0) { - throw new IllegalArgumentException("DNS server address array must not be empty"); - } - - this.header = new RdnssOption((byte) TYPE, (byte) (servers.length * 2 + 1), - (short) 0 /* reserved */, lifetime); - this.servers = servers.clone(); - } - - /** - * Parses an RDNSS option from a {@link ByteBuffer}. - * - * @param buf The buffer from which to parse the option. The buffer's byte order must be - * {@link java.nio.ByteOrder#BIG_ENDIAN}. - * @return the parsed option, or {@code null} if the option could not be parsed successfully. - */ - public static StructNdOptRdnss parse(@NonNull ByteBuffer buf) { - if (buf == null || buf.remaining() < MIN_OPTION_LEN * 8) return null; - try { - final RdnssOption header = Struct.parse(RdnssOption.class, buf); - if (header.type != TYPE) { - throw new IllegalArgumentException("Invalid type " + header.type); - } - if (header.length < MIN_OPTION_LEN || (header.length % 2 == 0)) { - throw new IllegalArgumentException("Invalid length " + header.length); - } - - final int numOfDnses = (header.length - 1) / 2; - final Inet6Address[] servers = new Inet6Address[numOfDnses]; - for (int i = 0; i < numOfDnses; i++) { - byte[] rawAddress = new byte[IPV6_ADDR_LEN]; - buf.get(rawAddress); - servers[i] = (Inet6Address) InetAddress.getByAddress(rawAddress); - } - return new StructNdOptRdnss(servers, header.lifetime); - } catch (IllegalArgumentException | BufferUnderflowException | UnknownHostException e) { - // Not great, but better than throwing an exception that might crash the caller. - // Convention in this package is that null indicates that the option was truncated - // or malformed, so callers must already handle it. - Log.d(TAG, "Invalid RDNSS option: " + e); - return null; - } - } - - protected void writeToByteBuffer(ByteBuffer buf) { - header.writeToByteBuffer(buf); - for (int i = 0; i < servers.length; i++) { - buf.put(servers[i].getAddress()); - } - } - - /** Outputs the wire format of the option to a new big-endian ByteBuffer. */ - public ByteBuffer toByteBuffer() { - final ByteBuffer buf = ByteBuffer.allocate(Struct.getSize(RdnssOption.class) - + servers.length * IPV6_ADDR_LEN); - writeToByteBuffer(buf); - buf.flip(); - return buf; - } - - @Override - @NonNull - public String toString() { - final StringJoiner sj = new StringJoiner(",", "[", "]"); - for (int i = 0; i < servers.length; i++) { - sj.add(servers[i].getHostAddress()); - } - return String.format("NdOptRdnss(%s,servers:%s)", header.toString(), sj.toString()); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java b/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java deleted file mode 100644 index 1f9bb7ec..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNdaCacheInfo.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2015 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 com.android.net.module.util.netlink; - -import static com.android.net.module.util.netlink.NetlinkUtils.ticksToMilliSeconds; - -import java.nio.ByteBuffer; - -/** - * struct nda_cacheinfo - * - * see: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class StructNdaCacheInfo { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse a nd cacheinfo netlink attribute from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the nd cacheinfo attribute. - * @return the parsed nd cacheinfo attribute, or {@code null} if the nd cacheinfo attribute - * could not be parsed successfully (for example, if it was truncated). - */ - public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) return null; - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - final StructNdaCacheInfo struct = new StructNdaCacheInfo(); - struct.ndm_used = byteBuffer.getInt(); - struct.ndm_confirmed = byteBuffer.getInt(); - struct.ndm_updated = byteBuffer.getInt(); - struct.ndm_refcnt = byteBuffer.getInt(); - return struct; - } - - /** - * Explanatory notes, for reference. - * - * Before being returned to user space, the neighbor entry times are - * converted to clock_t's like so: - * - * ndm_used = jiffies_to_clock_t(now - neigh->used); - * ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed); - * ndm_updated = jiffies_to_clock_t(now - neigh->updated); - * - * meaning that these values are expressed as "clock ticks ago". To - * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK). - * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed - * in centiseconds. - * - * These values are unsigned, but fortunately being expressed as "some - * clock ticks ago", these values are typically very small (and - * 2^31 centiseconds = 248 days). - * - * By observation, it appears that: - * ndm_used: the last time ARP/ND took place for this neighbor - * ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR - * higher layer confirmation (TCP or MSG_CONFIRM) - * was received - * ndm_updated: the time when the current NUD state was entered - */ - public int ndm_used; - public int ndm_confirmed; - public int ndm_updated; - public int ndm_refcnt; - - public StructNdaCacheInfo() {} - - /** - * The last time ARP/ND took place for this neighbor. - */ - public long lastUsed() { - return ticksToMilliSeconds(ndm_used); - } - - /** - * The last time ARP/ND succeeded for this neighbor or higher layer confirmation (TCP or - * MSG_CONFIRM) was received. - */ - public long lastConfirmed() { - return ticksToMilliSeconds(ndm_confirmed); - } - - /** - * The time when the current NUD state was entered. - */ - public long lastUpdated() { - return ticksToMilliSeconds(ndm_updated); - } - - @Override - public String toString() { - return "NdaCacheInfo{ " - + "ndm_used{" + lastUsed() + "}, " - + "ndm_confirmed{" + lastConfirmed() + "}, " - + "ndm_updated{" + lastUpdated() + "}, " - + "ndm_refcnt{" + ndm_refcnt + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java b/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java deleted file mode 100644 index 2de5490b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNfGenMsg.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Objects; - -/** - * struct nfgenmsg - * - * see <linux_src>/include/uapi/linux/netfilter/nfnetlink.h - * - * @hide - */ -public class StructNfGenMsg { - public static final int STRUCT_SIZE = 2 + Short.BYTES; - - public static final int NFNETLINK_V0 = 0; - - public final byte nfgen_family; - public final byte version; - public final short res_id; // N.B.: this is big endian in the kernel - - /** - * Parse a netfilter netlink header from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netfilter netlink header. - * @return the parsed netfilter netlink header, or {@code null} if the netfilter netlink header - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructNfGenMsg parse(@NonNull ByteBuffer byteBuffer) { - Objects.requireNonNull(byteBuffer); - - if (!hasAvailableSpace(byteBuffer)) return null; - - final byte nfgen_family = byteBuffer.get(); - final byte version = byteBuffer.get(); - - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.BIG_ENDIAN); - final short res_id = byteBuffer.getShort(); - byteBuffer.order(originalOrder); - - return new StructNfGenMsg(nfgen_family, version, res_id); - } - - public StructNfGenMsg(byte family, byte ver, short id) { - nfgen_family = family; - version = ver; - res_id = id; - } - - public StructNfGenMsg(byte family) { - nfgen_family = family; - version = (byte) NFNETLINK_V0; - res_id = (short) 0; - } - - /** - * Write a netfilter netlink header to a {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - byteBuffer.put(nfgen_family); - byteBuffer.put(version); - - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.BIG_ENDIAN); - byteBuffer.putShort(res_id); - byteBuffer.order(originalOrder); - } - - private static boolean hasAvailableSpace(@NonNull ByteBuffer byteBuffer) { - return byteBuffer.remaining() >= STRUCT_SIZE; - } - - @Override - public String toString() { - final String familyStr = NetlinkConstants.stringForAddressFamily(nfgen_family); - - return "NfGenMsg{ " - + "nfgen_family{" + familyStr + "}, " - + "version{" + Byte.toUnsignedInt(version) + "}, " - + "res_id{" + Short.toUnsignedInt(res_id) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlAttr.java b/common/device/com/android/net/module/util/netlink/StructNlAttr.java deleted file mode 100644 index a9b64950..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlAttr.java +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import android.net.MacAddress; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; - -/** - * struct nlattr - * - * see: <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlAttr { - // Already aligned. - public static final int NLA_HEADERLEN = 4; - public static final int NLA_F_NESTED = (1 << 15); - - /** - * Set carries nested attributes bit. - */ - public static short makeNestedType(short type) { - return (short) (type | NLA_F_NESTED); - } - - /** - * Peek and parse the netlink attribute from {@link ByteBuffer}. - * - * Return a (length, type) object only, without consuming any bytes in - * |byteBuffer| and without copying or interpreting any value bytes. - * This is used for scanning over a packed set of struct nlattr's, - * looking for instances of a particular type. - */ - public static StructNlAttr peek(ByteBuffer byteBuffer) { - if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) { - return null; - } - final int baseOffset = byteBuffer.position(); - - final StructNlAttr struct = new StructNlAttr(); - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.nativeOrder()); - try { - struct.nla_len = byteBuffer.getShort(); - struct.nla_type = byteBuffer.getShort(); - } finally { - byteBuffer.order(originalOrder); - } - - byteBuffer.position(baseOffset); - if (struct.nla_len < NLA_HEADERLEN) { - // Malformed. - return null; - } - return struct; - } - - /** - * Parse a netlink attribute from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink attriute. - * @return the parsed netlink attribute, or {@code null} if the netlink attribute - * could not be parsed successfully (for example, if it was truncated). - */ - public static StructNlAttr parse(ByteBuffer byteBuffer) { - final StructNlAttr struct = peek(byteBuffer); - if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) { - return null; - } - - final int baseOffset = byteBuffer.position(); - byteBuffer.position(baseOffset + NLA_HEADERLEN); - - int valueLen = ((int) struct.nla_len) & 0xffff; - valueLen -= NLA_HEADERLEN; - if (valueLen > 0) { - struct.nla_value = new byte[valueLen]; - byteBuffer.get(struct.nla_value, 0, valueLen); - byteBuffer.position(baseOffset + struct.getAlignedLength()); - } - return struct; - } - - /** - * Find next netlink attribute with a given type from {@link ByteBuffer}. - * - * @param attrType The given netlink attribute type is requested for. - * @param byteBuffer The buffer from which to find the netlink attribute. - * @return the found netlink attribute, or {@code null} if the netlink attribute could not be - * found or parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructNlAttr findNextAttrOfType(short attrType, - @Nullable ByteBuffer byteBuffer) { - while (byteBuffer != null && byteBuffer.remaining() > 0) { - final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer); - if (nlAttr == null) { - break; - } - if (nlAttr.nla_type == attrType) { - return StructNlAttr.parse(byteBuffer); - } - if (byteBuffer.remaining() < nlAttr.getAlignedLength()) { - break; - } - byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength()); - } - return null; - } - - public short nla_len = (short) NLA_HEADERLEN; - public short nla_type; - public byte[] nla_value; - - public StructNlAttr() {} - - public StructNlAttr(short type, byte value) { - nla_type = type; - setValue(new byte[1]); - nla_value[0] = value; - } - - public StructNlAttr(short type, short value) { - this(type, value, ByteOrder.nativeOrder()); - } - - public StructNlAttr(short type, short value, ByteOrder order) { - nla_type = type; - setValue(new byte[Short.BYTES]); - final ByteBuffer buf = getValueAsByteBuffer(); - final ByteOrder originalOrder = buf.order(); - try { - buf.order(order); - buf.putShort(value); - } finally { - buf.order(originalOrder); - } - } - - public StructNlAttr(short type, int value) { - this(type, value, ByteOrder.nativeOrder()); - } - - public StructNlAttr(short type, int value, ByteOrder order) { - nla_type = type; - setValue(new byte[Integer.BYTES]); - final ByteBuffer buf = getValueAsByteBuffer(); - final ByteOrder originalOrder = buf.order(); - try { - buf.order(order); - buf.putInt(value); - } finally { - buf.order(originalOrder); - } - } - - public StructNlAttr(short type, @NonNull final byte[] value) { - nla_type = type; - setValue(value); - } - - public StructNlAttr(short type, @NonNull final InetAddress ip) { - nla_type = type; - setValue(ip.getAddress()); - } - - public StructNlAttr(short type, @NonNull final MacAddress mac) { - nla_type = type; - setValue(mac.toByteArray()); - } - - public StructNlAttr(short type, @NonNull final String string) { - nla_type = type; - byte[] value = null; - try { - final byte[] stringBytes = string.getBytes("UTF-8"); - // Append '\0' at the end of interface name string bytes. - value = Arrays.copyOf(stringBytes, stringBytes.length + 1); - } catch (UnsupportedEncodingException ignored) { - // Do nothing. - } finally { - setValue(value); - } - } - - public StructNlAttr(short type, StructNlAttr... nested) { - this(); - nla_type = makeNestedType(type); - - int payloadLength = 0; - for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength(); - setValue(new byte[payloadLength]); - - final ByteBuffer buf = getValueAsByteBuffer(); - for (StructNlAttr nla : nested) { - nla.pack(buf); - } - } - - /** - * Get aligned attribute length. - */ - public int getAlignedLength() { - return NetlinkConstants.alignedLengthOf(nla_len); - } - - /** - * Get attribute value as BE16. - */ - public short getValueAsBe16(short defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Short.BYTES) { - return defaultValue; - } - final ByteOrder originalOrder = byteBuffer.order(); - try { - byteBuffer.order(ByteOrder.BIG_ENDIAN); - return byteBuffer.getShort(); - } finally { - byteBuffer.order(originalOrder); - } - } - - /** - * Get attribute value as BE32. - */ - public int getValueAsBe32(int defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return defaultValue; - } - final ByteOrder originalOrder = byteBuffer.order(); - try { - byteBuffer.order(ByteOrder.BIG_ENDIAN); - return byteBuffer.getInt(); - } finally { - byteBuffer.order(originalOrder); - } - } - - /** - * Get attribute value as ByteBuffer. - */ - public ByteBuffer getValueAsByteBuffer() { - if (nla_value == null) return null; - final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); - // By convention, all buffers in this library are in native byte order because netlink is in - // native byte order. It's the order that is used by NetlinkSocket.recvMessage and the only - // order accepted by NetlinkMessage.parse. - byteBuffer.order(ByteOrder.nativeOrder()); - return byteBuffer; - } - - /** - * Get attribute value as byte. - */ - public byte getValueAsByte(byte defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Byte.BYTES) { - return defaultValue; - } - return getValueAsByteBuffer().get(); - } - - /** - * Get attribute value as Integer, or null if malformed (e.g., length is not 4 bytes). - */ - public Integer getValueAsInteger() { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return null; - } - return byteBuffer.getInt(); - } - - /** - * Get attribute value as Int, default value if malformed. - */ - public int getValueAsInt(int defaultValue) { - final Integer value = getValueAsInteger(); - return (value != null) ? value : defaultValue; - } - - /** - * Get attribute value as InetAddress. - * - * @return the InetAddress instance representation of attribute value or null if IP address - * is of illegal length. - */ - @Nullable - public InetAddress getValueAsInetAddress() { - if (nla_value == null) return null; - - try { - return InetAddress.getByAddress(nla_value); - } catch (UnknownHostException ignored) { - return null; - } - } - - /** - * Get attribute value as MacAddress. - * - * @return the MacAddress instance representation of attribute value or null if the given byte - * array is not a valid representation(e.g, not all link layers have 6-byte link-layer - * addresses) - */ - @Nullable - public MacAddress getValueAsMacAddress() { - if (nla_value == null) return null; - - try { - return MacAddress.fromBytes(nla_value); - } catch (IllegalArgumentException ignored) { - return null; - } - } - - /** - * Get attribute value as a unicode string. - * - * @return a unicode string or null if UTF-8 charset is not supported. - */ - @Nullable - public String getValueAsString() { - if (nla_value == null) return null; - // Check the attribute value length after removing string termination flag '\0'. - // This assumes that all netlink strings are null-terminated. - if (nla_value.length < (nla_len - NLA_HEADERLEN - 1)) return null; - - try { - final byte[] array = Arrays.copyOf(nla_value, nla_len - NLA_HEADERLEN - 1); - return new String(array, "UTF-8"); - } catch (UnsupportedEncodingException | NegativeArraySizeException ignored) { - return null; - } - } - - /** - * Write the netlink attribute to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - final ByteOrder originalOrder = byteBuffer.order(); - final int originalPosition = byteBuffer.position(); - - byteBuffer.order(ByteOrder.nativeOrder()); - try { - byteBuffer.putShort(nla_len); - byteBuffer.putShort(nla_type); - if (nla_value != null) byteBuffer.put(nla_value); - } finally { - byteBuffer.order(originalOrder); - } - byteBuffer.position(originalPosition + getAlignedLength()); - } - - private void setValue(byte[] value) { - nla_value = value; - nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0)); - } - - @Override - public String toString() { - return "StructNlAttr{ " - + "nla_len{" + nla_len + "}, " - + "nla_type{" + nla_type + "}, " - + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java b/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java deleted file mode 100644 index b6620f3b..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlMsgErr.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import java.nio.ByteBuffer; - -/** - * struct nlmsgerr - * - * see <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlMsgErr { - public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE; - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse a netlink error message payload from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the netlink error message payload. - * @return the parsed netlink error message payload, or {@code null} if the netlink error - * message payload could not be parsed successfully (for example, if it was truncated). - */ - public static StructNlMsgErr parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) return null; - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - final StructNlMsgErr struct = new StructNlMsgErr(); - struct.error = byteBuffer.getInt(); - struct.msg = StructNlMsgHdr.parse(byteBuffer); - return struct; - } - - public int error; - public StructNlMsgHdr msg; - - /** - * Write the netlink error message payload to {@link ByteBuffer}. - */ - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - byteBuffer.putInt(error); - if (msg != null) { - msg.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "StructNlMsgErr{ " - + "error{" + error + "}, " - + "msg{" + (msg == null ? "" : msg.toString()) + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java b/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java deleted file mode 100644 index 5052cb8a..00000000 --- a/common/device/com/android/net/module/util/netlink/StructNlMsgHdr.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2019 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.nio.ByteBuffer; - -/** - * struct nlmsghdr - * - * see <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlMsgHdr { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - public static final short NLM_F_REQUEST = 0x0001; - public static final short NLM_F_MULTI = 0x0002; - public static final short NLM_F_ACK = 0x0004; - public static final short NLM_F_ECHO = 0x0008; - // Flags for a GET request. - public static final short NLM_F_ROOT = 0x0100; - public static final short NLM_F_MATCH = 0x0200; - public static final short NLM_F_DUMP = NLM_F_ROOT | NLM_F_MATCH; - // Flags for a NEW request. - public static final short NLM_F_REPLACE = 0x100; - public static final short NLM_F_EXCL = 0x200; - public static final short NLM_F_CREATE = 0x400; - public static final short NLM_F_APPEND = 0x800; - - // TODO: Probably need to distinguish the flags which have the same value. For example, - // NLM_F_MATCH (0x200) and NLM_F_EXCL (0x200). - private static String stringForNlMsgFlags(short flags) { - final StringBuilder sb = new StringBuilder(); - if ((flags & NLM_F_REQUEST) != 0) { - sb.append("NLM_F_REQUEST"); - } - if ((flags & NLM_F_MULTI) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NLM_F_MULTI"); - } - if ((flags & NLM_F_ACK) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NLM_F_ACK"); - } - if ((flags & NLM_F_ECHO) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NLM_F_ECHO"); - } - if ((flags & NLM_F_ROOT) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NLM_F_ROOT"); - } - if ((flags & NLM_F_MATCH) != 0) { - if (sb.length() > 0) { - sb.append("|"); - } - sb.append("NLM_F_MATCH"); - } - return sb.toString(); - } - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - /** - * Parse netlink message header from buffer. - */ - @Nullable - public static StructNlMsgHdr parse(@NonNull ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) return null; - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - final StructNlMsgHdr struct = new StructNlMsgHdr(); - struct.nlmsg_len = byteBuffer.getInt(); - struct.nlmsg_type = byteBuffer.getShort(); - struct.nlmsg_flags = byteBuffer.getShort(); - struct.nlmsg_seq = byteBuffer.getInt(); - struct.nlmsg_pid = byteBuffer.getInt(); - - if (struct.nlmsg_len < STRUCT_SIZE) { - // Malformed. - return null; - } - return struct; - } - - public int nlmsg_len; - public short nlmsg_type; - public short nlmsg_flags; - public int nlmsg_seq; - public int nlmsg_pid; - - public StructNlMsgHdr() { - nlmsg_len = 0; - nlmsg_type = 0; - nlmsg_flags = 0; - nlmsg_seq = 0; - nlmsg_pid = 0; - } - - /** - * Write netlink message header to ByteBuffer. - */ - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - byteBuffer.putInt(nlmsg_len); - byteBuffer.putShort(nlmsg_type); - byteBuffer.putShort(nlmsg_flags); - byteBuffer.putInt(nlmsg_seq); - byteBuffer.putInt(nlmsg_pid); - } - - @Override - public String toString() { - return toString(null /* unknown netlink family */); - } - - /** - * Transform a netlink header into a string. The netlink family is required for transforming - * a netlink type integer into a string. - * @param nlFamily netlink family. Using Integer will not incur autoboxing penalties because - * family values are small, and all Integer objects between -128 and 127 are - * statically cached. See Integer.IntegerCache. - * @return A list of header elements. - */ - @NonNull - public String toString(@Nullable Integer nlFamily) { - final String typeStr = "" + nlmsg_type - + "(" + (nlFamily == null - ? "" : NetlinkConstants.stringForNlMsgType(nlmsg_type, nlFamily)) - + ")"; - final String flagsStr = "" + nlmsg_flags - + "(" + stringForNlMsgFlags(nlmsg_flags) + ")"; - return "StructNlMsgHdr{ " - + "nlmsg_len{" + nlmsg_len + "}, " - + "nlmsg_type{" + typeStr + "}, " - + "nlmsg_flags{" + flagsStr + "}, " - + "nlmsg_seq{" + nlmsg_seq + "}, " - + "nlmsg_pid{" + nlmsg_pid + "} " - + "}"; - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructRtMsg.java b/common/device/com/android/net/module/util/netlink/StructRtMsg.java deleted file mode 100644 index 3cd72922..00000000 --- a/common/device/com/android/net/module/util/netlink/StructRtMsg.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct rtmsg - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructRtMsg extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 12; - - @Field(order = 0, type = Type.U8) - public final short family; // Address family of route. - @Field(order = 1, type = Type.U8) - public final short dstLen; // Length of destination. - @Field(order = 2, type = Type.U8) - public final short srcLen; // Length of source. - @Field(order = 3, type = Type.U8) - public final short tos; // TOS filter. - @Field(order = 4, type = Type.U8) - public final short table; // Routing table ID. - @Field(order = 5, type = Type.U8) - public final short protocol; // Routing protocol. - @Field(order = 6, type = Type.U8) - public final short scope; // distance to the destination. - @Field(order = 7, type = Type.U8) - public final short type; // route type - @Field(order = 8, type = Type.U32) - public final long flags; - - StructRtMsg(short family, short dstLen, short srcLen, short tos, short table, short protocol, - short scope, short type, long flags) { - this.family = family; - this.dstLen = dstLen; - this.srcLen = srcLen; - this.tos = tos; - this.table = table; - this.protocol = protocol; - this.scope = scope; - this.type = type; - this.flags = flags; - } - - /** - * Parse a rtmsg struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the rtmsg struct. - * @return the parsed rtmsg struct, or {@code null} if the rtmsg struct could not be - * parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructRtMsg parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructRtMsg.class, byteBuffer); - } - - /** - * Write the rtmsg struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java b/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java deleted file mode 100644 index fef1f9e8..00000000 --- a/common/device/com/android/net/module/util/netlink/StructRtaCacheInfo.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.netlink; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; - -/** - * struct rta_cacheinfo - * - * see also: - * - * include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class StructRtaCacheInfo extends Struct { - // Already aligned. - public static final int STRUCT_SIZE = 32; - - @Field(order = 0, type = Type.U32) - public final long clntref; - @Field(order = 1, type = Type.U32) - public final long lastuse; - @Field(order = 2, type = Type.S32) - public final int expires; - @Field(order = 3, type = Type.U32) - public final long error; - @Field(order = 4, type = Type.U32) - public final long used; - @Field(order = 5, type = Type.U32) - public final long id; - @Field(order = 6, type = Type.U32) - public final long ts; - @Field(order = 7, type = Type.U32) - public final long tsage; - - StructRtaCacheInfo(long clntref, long lastuse, int expires, long error, long used, long id, - long ts, long tsage) { - this.clntref = clntref; - this.lastuse = lastuse; - this.expires = expires; - this.error = error; - this.used = used; - this.id = id; - this.ts = ts; - this.tsage = tsage; - } - - /** - * Parse an rta_cacheinfo struct from a {@link ByteBuffer}. - * - * @param byteBuffer The buffer from which to parse the rta_cacheinfo. - * @return the parsed rta_cacheinfo struct, or {@code null} if the rta_cacheinfo struct - * could not be parsed successfully (for example, if it was truncated). - */ - @Nullable - public static StructRtaCacheInfo parse(@NonNull final ByteBuffer byteBuffer) { - if (byteBuffer.remaining() < STRUCT_SIZE) return null; - - // The ByteOrder must already have been set to native order. - return Struct.parse(StructRtaCacheInfo.class, byteBuffer); - } - - /** - * Write a rta_cacheinfo struct to {@link ByteBuffer}. - */ - public void pack(@NonNull final ByteBuffer byteBuffer) { - // The ByteOrder must already have been set to native order. - this.writeToByteBuffer(byteBuffer); - } -} diff --git a/common/device/com/android/net/module/util/structs/EthernetHeader.java b/common/device/com/android/net/module/util/structs/EthernetHeader.java deleted file mode 100644 index 92ef8a7e..00000000 --- a/common/device/com/android/net/module/util/structs/EthernetHeader.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import android.net.MacAddress; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * L2 ethernet header as per IEEE 802.3. Does not include a 802.1Q tag. - * - * 0 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Destination | - * +- -+ - * | Ethernet | - * +- -+ - * | Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source | - * +- -+ - * | Ethernet | - * +- -+ - * | Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | EtherType | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class EthernetHeader extends Struct { - @Field(order = 0, type = Type.EUI48) - public final MacAddress dstMac; - @Field(order = 1, type = Type.EUI48) - public final MacAddress srcMac; - @Field(order = 2, type = Type.U16) - public final int etherType; - - public EthernetHeader(final MacAddress dstMac, final MacAddress srcMac, - final int etherType) { - this.dstMac = dstMac; - this.srcMac = srcMac; - this.etherType = etherType; - } -} diff --git a/common/device/com/android/net/module/util/structs/IaPdOption.java b/common/device/com/android/net/module/util/structs/IaPdOption.java deleted file mode 100644 index dbf79dcb..00000000 --- a/common/device/com/android/net/module/util/structs/IaPdOption.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IA_PD; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * DHCPv6 IA_PD option. - * https://tools.ietf.org/html/rfc8415. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | OPTION_IA_PD | option-len | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | IAID (4 octets) | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | T1 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | T2 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * . . - * . IA_PD-options . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - */ -public class IaPdOption extends Struct { - public static final int LENGTH = 12; // option length excluding IA_PD options - - @Field(order = 0, type = Type.S16) - public final short code; - @Field(order = 1, type = Type.S16) - public final short length; - @Field(order = 2, type = Type.U32) - public final long id; - @Field(order = 3, type = Type.U32) - public final long t1; - @Field(order = 4, type = Type.U32) - public final long t2; - - IaPdOption(final short code, final short length, final long id, final long t1, - final long t2) { - this.code = code; - this.length = length; - this.id = id; - this.t1 = t1; - this.t2 = t2; - } - - /** - * Build an IA_PD option from the required specific parameters. - */ - public static ByteBuffer build(final short length, final long id, final long t1, - final long t2) { - final IaPdOption option = new IaPdOption((short) DHCP6_OPTION_IA_PD, - length /* 12 + IA_PD options length */, id, t1, t2); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/IaPrefixOption.java b/common/device/com/android/net/module/util/structs/IaPrefixOption.java deleted file mode 100644 index f0e44098..00000000 --- a/common/device/com/android/net/module/util/structs/IaPrefixOption.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAPREFIX; - -import androidx.annotation.VisibleForTesting; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * DHCPv6 IA Prefix Option. - * https://tools.ietf.org/html/rfc8415. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | OPTION_IAPREFIX | option-len | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | preferred-lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | valid-lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | prefix-length | | - * +-+-+-+-+-+-+-+-+ IPv6-prefix | - * | (16 octets) | - * | | - * | | - * | | - * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | . - * +-+-+-+-+-+-+-+-+ . - * . IAprefix-options . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class IaPrefixOption extends Struct { - public static final int LENGTH = 25; // option length excluding IAprefix-options - - @Field(order = 0, type = Type.S16) - public final short code; - @Field(order = 1, type = Type.S16) - public final short length; - @Field(order = 2, type = Type.U32) - public final long preferred; - @Field(order = 3, type = Type.U32) - public final long valid; - @Field(order = 4, type = Type.S8) - public final byte prefixLen; - @Field(order = 5, type = Type.ByteArray, arraysize = 16) - public final byte[] prefix; - - @VisibleForTesting - public IaPrefixOption(final short code, final short length, final long preferred, - final long valid, final byte prefixLen, final byte[] prefix) { - this.code = code; - this.length = length; - this.preferred = preferred; - this.valid = valid; - this.prefixLen = prefixLen; - this.prefix = prefix.clone(); - } - - /** - * Build an IA_PD prefix option with given specific parameters. - */ - public static ByteBuffer build(final short length, final long preferred, final long valid, - final byte prefixLen, final byte[] prefix) { - final IaPrefixOption option = new IaPrefixOption((byte) DHCP6_OPTION_IAPREFIX, - length /* 25 + IAPrefix options length */, preferred, valid, prefixLen, prefix); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/Icmpv4Header.java b/common/device/com/android/net/module/util/structs/Icmpv4Header.java deleted file mode 100644 index 454bb074..00000000 --- a/common/device/com/android/net/module/util/structs/Icmpv4Header.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv4 header as per https://tools.ietf.org/html/rfc792. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Icmpv4Header extends Struct { - @Field(order = 0, type = Type.U8) - public short type; - @Field(order = 1, type = Type.U8) - public short code; - @Field(order = 2, type = Type.S16) - public short checksum; - public Icmpv4Header(final short type, final short code, final short checksum) { - this.type = type; - this.code = code; - this.checksum = checksum; - } -} diff --git a/common/device/com/android/net/module/util/structs/Icmpv6Header.java b/common/device/com/android/net/module/util/structs/Icmpv6Header.java deleted file mode 100644 index c82ae02b..00000000 --- a/common/device/com/android/net/module/util/structs/Icmpv6Header.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 header as per https://tools.ietf.org/html/rfc4443. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Icmpv6Header extends Struct { - @Field(order = 0, type = Type.U8) - public short type; - @Field(order = 1, type = Type.U8) - public short code; - @Field(order = 2, type = Type.S16) - public short checksum; - - public Icmpv6Header(final short type, final short code, final short checksum) { - this.type = type; - this.code = code; - this.checksum = checksum; - } -} diff --git a/common/device/com/android/net/module/util/structs/Ipv4Header.java b/common/device/com/android/net/module/util/structs/Ipv4Header.java deleted file mode 100644 index 5249454c..00000000 --- a/common/device/com/android/net/module/util/structs/Ipv4Header.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import androidx.annotation.VisibleForTesting; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet4Address; - -/** - * L3 IPv4 header as per https://tools.ietf.org/html/rfc791. - * This class doesn't contain options field. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| IHL |Type of Service| Total Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Identification |Flags| Fragment Offset | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Time to Live | Protocol | Header Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Destination Address | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Ipv4Header extends Struct { - // IP Version=IPv4, IHL is always 5(*4bytes) because options are not supported. - @VisibleForTesting - public static final byte IPHDR_VERSION_IHL = 0x45; - - @Field(order = 0, type = Type.S8) - // version (4 bits), IHL (4 bits) - public final byte vi; - @Field(order = 1, type = Type.S8) - public final byte tos; - @Field(order = 2, type = Type.U16) - public final int totalLength; - @Field(order = 3, type = Type.S16) - public final short id; - @Field(order = 4, type = Type.S16) - // flags (3 bits), fragment offset (13 bits) - public final short flagsAndFragmentOffset; - @Field(order = 5, type = Type.U8) - public final short ttl; - @Field(order = 6, type = Type.S8) - public final byte protocol; - @Field(order = 7, type = Type.S16) - public final short checksum; - @Field(order = 8, type = Type.Ipv4Address) - public final Inet4Address srcIp; - @Field(order = 9, type = Type.Ipv4Address) - public final Inet4Address dstIp; - - public Ipv4Header(final byte tos, final int totalLength, final short id, - final short flagsAndFragmentOffset, final short ttl, final byte protocol, - final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) { - this(IPHDR_VERSION_IHL, tos, totalLength, id, flagsAndFragmentOffset, ttl, - protocol, checksum, srcIp, dstIp); - } - - private Ipv4Header(final byte vi, final byte tos, final int totalLength, final short id, - final short flagsAndFragmentOffset, final short ttl, final byte protocol, - final short checksum, final Inet4Address srcIp, final Inet4Address dstIp) { - this.vi = vi; - this.tos = tos; - this.totalLength = totalLength; - this.id = id; - this.flagsAndFragmentOffset = flagsAndFragmentOffset; - this.ttl = ttl; - this.protocol = protocol; - this.checksum = checksum; - this.srcIp = srcIp; - this.dstIp = dstIp; - } -} diff --git a/common/device/com/android/net/module/util/structs/Ipv6Header.java b/common/device/com/android/net/module/util/structs/Ipv6Header.java deleted file mode 100644 index a14e064d..00000000 --- a/common/device/com/android/net/module/util/structs/Ipv6Header.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * L3 IPv6 header as per https://tools.ietf.org/html/rfc8200. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |Version| Traffic Class | Flow Label | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Payload Length | Next Header | Hop Limit | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Source Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Destination Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class Ipv6Header extends Struct { - @Field(order = 0, type = Type.S32) - public int vtf; - @Field(order = 1, type = Type.U16) - public int payloadLength; - @Field(order = 2, type = Type.S8) - public byte nextHeader; - @Field(order = 3, type = Type.U8) - public short hopLimit; - @Field(order = 4, type = Type.Ipv6Address) - public Inet6Address srcIp; - @Field(order = 5, type = Type.Ipv6Address) - public Inet6Address dstIp; - - public Ipv6Header(final int vtf, final int payloadLength, final byte nextHeader, - final short hopLimit, final Inet6Address srcIp, final Inet6Address dstIp) { - this.vtf = vtf; - this.payloadLength = payloadLength; - this.nextHeader = nextHeader; - this.hopLimit = hopLimit; - this.srcIp = srcIp; - this.dstIp = dstIp; - } -} diff --git a/common/device/com/android/net/module/util/structs/Ipv6PktInfo.java b/common/device/com/android/net/module/util/structs/Ipv6PktInfo.java deleted file mode 100644 index 0dccb727..00000000 --- a/common/device/com/android/net/module/util/structs/Ipv6PktInfo.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * structure in6_pktinfo - * - * see also: - * - * include/uapi/linux/ipv6.h - */ -public class Ipv6PktInfo extends Struct { - @Field(order = 0, type = Type.Ipv6Address) - public final Inet6Address addr; // IPv6 source or destination address - @Field(order = 1, type = Type.S32) - public final int ifindex; // interface index - - public Ipv6PktInfo(final Inet6Address addr, final int ifindex) { - this.addr = addr; - this.ifindex = ifindex; - } -} diff --git a/common/device/com/android/net/module/util/structs/LlaOption.java b/common/device/com/android/net/module/util/structs/LlaOption.java deleted file mode 100644 index fbaccabc..00000000 --- a/common/device/com/android/net/module/util/structs/LlaOption.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import android.net.MacAddress; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 source/target link-layer address option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Link-Layer Address ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class LlaOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.EUI48) - // Link layer address length and format varies on different link layers, which is not - // guaranteed to be a 6-byte MAC address. However, Struct only supports 6-byte MAC - // addresses type(EUI-48) for now. - public final MacAddress linkLayerAddress; - - LlaOption(final byte type, final byte length, final MacAddress linkLayerAddress) { - this.type = type; - this.length = length; - this.linkLayerAddress = linkLayerAddress; - } - - /** - * Build a target link-layer address option from the required specified parameters. - */ - public static ByteBuffer build(final byte type, final MacAddress linkLayerAddress) { - final LlaOption option = new LlaOption(type, (byte) 1 /* option len */, linkLayerAddress); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/MtuOption.java b/common/device/com/android/net/module/util/structs/MtuOption.java deleted file mode 100644 index 34bc21c1..00000000 --- a/common/device/com/android/net/module/util/structs/MtuOption.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 MTU option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | MTU | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class MtuOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S16) - public final short reserved; - @Field(order = 3, type = Type.U32) - public final long mtu; - - MtuOption(final byte type, final byte length, final short reserved, - final long mtu) { - this.type = type; - this.length = length; - this.reserved = reserved; - this.mtu = mtu; - } - - /** - * Build a MTU option from the required specified parameters. - */ - public static ByteBuffer build(final long mtu) { - final MtuOption option = new MtuOption((byte) ICMPV6_ND_OPTION_MTU, - (byte) 1 /* option len */, (short) 0 /* reserved */, mtu); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/NaHeader.java b/common/device/com/android/net/module/util/structs/NaHeader.java deleted file mode 100644 index 90c078e8..00000000 --- a/common/device/com/android/net/module/util/structs/NaHeader.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * ICMPv6 Neighbor Advertisement header, follow {@link Icmpv6Header}, as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |R|S|O| Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Target Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class NaHeader extends Struct { - @Field(order = 0, type = Type.S32) - public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits. - @Field(order = 1, type = Type.Ipv6Address) - public Inet6Address target; - - public NaHeader(final int flags, final Inet6Address target) { - this.flags = flags; - this.target = target; - } -} diff --git a/common/device/com/android/net/module/util/structs/NsHeader.java b/common/device/com/android/net/module/util/structs/NsHeader.java deleted file mode 100644 index 2e8b77ba..00000000 --- a/common/device/com/android/net/module/util/structs/NsHeader.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; - -/** - * ICMPv6 Neighbor Solicitation header, follow {@link Icmpv6Header}, as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Target Address + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class NsHeader extends Struct { - @Field(order = 0, type = Type.S32) - public int reserved; // 32 Reserved bits. - @Field(order = 1, type = Type.Ipv6Address) - public Inet6Address target; - - NsHeader(int reserved, final Inet6Address target) { - this.reserved = reserved; - this.target = target; - } - - public NsHeader(final Inet6Address target) { - this(0, target); - } -} diff --git a/common/device/com/android/net/module/util/structs/PrefixInformationOption.java b/common/device/com/android/net/module/util/structs/PrefixInformationOption.java deleted file mode 100644 index 49d7654d..00000000 --- a/common/device/com/android/net/module/util/structs/PrefixInformationOption.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_PIO; - -import android.net.IpPrefix; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 prefix information option, as per https://tools.ietf.org/html/rfc4861. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Prefix Length |L|A| Reserved1 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Valid Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Preferred Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved2 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * + + - * | | - * + Prefix + - * | | - * + + - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class PrefixInformationOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S8) - public final byte prefixLen; - @Field(order = 3, type = Type.S8) - // On-link flag, Autonomous address configuration flag, 6-reserved bits - public final byte flags; - @Field(order = 4, type = Type.U32) - public final long validLifetime; - @Field(order = 5, type = Type.U32) - public final long preferredLifetime; - @Field(order = 6, type = Type.S32) - public final int reserved; - @Field(order = 7, type = Type.ByteArray, arraysize = 16) - public final byte[] prefix; - - PrefixInformationOption(final byte type, final byte length, final byte prefixLen, - final byte flags, final long validLifetime, final long preferredLifetime, - final int reserved, @NonNull final byte[] prefix) { - this.type = type; - this.length = length; - this.prefixLen = prefixLen; - this.flags = flags; - this.validLifetime = validLifetime; - this.preferredLifetime = preferredLifetime; - this.reserved = reserved; - this.prefix = prefix; - } - - /** - * Build a Prefix Information option from the required specified parameters. - */ - public static ByteBuffer build(final IpPrefix prefix, final byte flags, - final long validLifetime, final long preferredLifetime) { - final PrefixInformationOption option = new PrefixInformationOption( - (byte) ICMPV6_ND_OPTION_PIO, (byte) 4 /* option len */, - (byte) prefix.getPrefixLength(), flags, validLifetime, preferredLifetime, - (int) 0, prefix.getRawAddress()); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/RaHeader.java b/common/device/com/android/net/module/util/structs/RaHeader.java deleted file mode 100644 index 31a5cb76..00000000 --- a/common/device/com/android/net/module/util/structs/RaHeader.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 Router Advertisement header, follow [Icmpv6Header], as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Cur Hop Limit |M|O| Reserved | Router Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reachable Time | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Retrans Timer | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class RaHeader extends Struct { - @Field(order = 0, type = Type.S8) - public final byte hopLimit; - // "Managed address configuration", "Other configuration" bits, and 6 reserved bits - @Field(order = 1, type = Type.S8) - public final byte flags; - @Field(order = 2, type = Type.U16) - public final int lifetime; - @Field(order = 3, type = Type.U32) - public final long reachableTime; - @Field(order = 4, type = Type.U32) - public final long retransTimer; - - public RaHeader(final byte hopLimit, final byte flags, final int lifetime, - final long reachableTime, final long retransTimer) { - this.hopLimit = hopLimit; - this.flags = flags; - this.lifetime = lifetime; - this.reachableTime = reachableTime; - this.retransTimer = retransTimer; - } -} diff --git a/common/device/com/android/net/module/util/structs/RdnssOption.java b/common/device/com/android/net/module/util/structs/RdnssOption.java deleted file mode 100644 index 4a5bd7e9..00000000 --- a/common/device/com/android/net/module/util/structs/RdnssOption.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RDNSS; - -import android.net.InetAddresses; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.net.Inet6Address; -import java.nio.ByteBuffer; - -/** - * IPv6 RA recursive DNS server option, as per https://tools.ietf.org/html/rfc8106. - * This should be followed by a series of DNSv6 server addresses. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * : Addresses of IPv6 Recursive DNS Servers : - * | | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class RdnssOption extends Struct { - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte units - @Field(order = 2, type = Type.S16) - public final short reserved; - @Field(order = 3, type = Type.U32) - public final long lifetime; - - public RdnssOption(final byte type, final byte length, final short reserved, - final long lifetime) { - this.type = type; - this.length = length; - this.reserved = reserved; - this.lifetime = lifetime; - } - - /** - * Build a RDNSS option from the required specified Inet6Address parameters. - */ - public static ByteBuffer build(final long lifetime, final Inet6Address... servers) { - final byte length = (byte) (1 + 2 * servers.length); - final RdnssOption option = new RdnssOption((byte) ICMPV6_ND_OPTION_RDNSS, - length, (short) 0, lifetime); - final ByteBuffer buffer = ByteBuffer.allocate(length * 8); - option.writeToByteBuffer(buffer); - for (Inet6Address server : servers) { - buffer.put(server.getAddress()); - } - buffer.flip(); - return buffer; - } - - /** - * Build a RDNSS option from the required specified String parameters. - * - * @throws IllegalArgumentException if {@code servers} does not contain only numeric addresses. - */ - public static ByteBuffer build(final long lifetime, final String... servers) { - final Inet6Address[] serverArray = new Inet6Address[servers.length]; - for (int i = 0; i < servers.length; i++) { - serverArray[i] = (Inet6Address) InetAddresses.parseNumericAddress(servers[i]); - } - return build(lifetime, serverArray); - } -} diff --git a/common/device/com/android/net/module/util/structs/RouteInformationOption.java b/common/device/com/android/net/module/util/structs/RouteInformationOption.java deleted file mode 100644 index 49bafedb..00000000 --- a/common/device/com/android/net/module/util/structs/RouteInformationOption.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.structs; - -import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_RIO; - -import android.net.IpPrefix; - -import androidx.annotation.NonNull; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * ICMPv6 route information option, as per https://tools.ietf.org/html/rfc4191. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Length | Prefix Length |Resvd|Prf|Resvd| - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Route Lifetime | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Prefix (Variable Length) | - * . . - * . . - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class RouteInformationOption extends Struct { - public enum Preference { - HIGH((byte) 0x1), - MEDIUM((byte) 0x0), - LOW((byte) 0x3), - RESERVED((byte) 0x2); - - final byte mValue; - Preference(byte value) { - this.mValue = value; - } - } - - @Field(order = 0, type = Type.S8) - public final byte type; - @Field(order = 1, type = Type.S8) - public final byte length; // Length in 8-byte octets - @Field(order = 2, type = Type.U8) - public final short prefixLen; - @Field(order = 3, type = Type.S8) - public final byte prf; - @Field(order = 4, type = Type.U32) - public final long routeLifetime; - @Field(order = 5, type = Type.ByteArray, arraysize = 16) - public final byte[] prefix; - - RouteInformationOption(final byte type, final byte length, final short prefixLen, - final byte prf, final long routeLifetime, @NonNull final byte[] prefix) { - this.type = type; - this.length = length; - this.prefixLen = prefixLen; - this.prf = prf; - this.routeLifetime = routeLifetime; - this.prefix = prefix; - } - - /** - * Build a Route Information option from the required specified parameters. - */ - public static ByteBuffer build(final IpPrefix prefix, final Preference prf, - final long routeLifetime) { - // The prefix field is always assumed to have 16 bytes, but the number of leading - // bits in this prefix depends on IpPrefix#prefixLength, then we can simply set the - // option length to 3. - final RouteInformationOption option = new RouteInformationOption( - (byte) ICMPV6_ND_OPTION_RIO, (byte) 3 /* option length */, - (short) prefix.getPrefixLength(), (byte) (prf.mValue << 3), routeLifetime, - prefix.getRawAddress()); - return ByteBuffer.wrap(option.writeToBytes(ByteOrder.BIG_ENDIAN)); - } -} diff --git a/common/device/com/android/net/module/util/structs/RsHeader.java b/common/device/com/android/net/module/util/structs/RsHeader.java deleted file mode 100644 index 0b51ff25..00000000 --- a/common/device/com/android/net/module/util/structs/RsHeader.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * ICMPv6 Router Solicitation header, follow [Icmpv6Header], as per - * https://tools.ietf.org/html/rfc4861. This does not contain any option. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type | Code | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Reserved | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options ... - * +-+-+-+-+-+-+-+-+-+-+-+- - */ -public class RsHeader extends Struct { - @Field(order = 0, type = Type.S32) - public final int reserved; - - public RsHeader(final int reserved) { - this.reserved = reserved; - } -} diff --git a/common/device/com/android/net/module/util/structs/TcpHeader.java b/common/device/com/android/net/module/util/structs/TcpHeader.java deleted file mode 100644 index 0c97401c..00000000 --- a/common/device/com/android/net/module/util/structs/TcpHeader.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * L4 TCP header as per https://tools.ietf.org/html/rfc793. - * This class does not contain option and data fields. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Port | Destination Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Sequence Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Acknowledgment Number | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Data | |U|A|P|R|S|F| | - * | Offset| Reserved |R|C|S|S|Y|I| Window | - * | | |G|K|H|T|N|N| | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Checksum | Urgent Pointer | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Options | Padding | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | data | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -public class TcpHeader extends Struct { - @Field(order = 0, type = Type.U16) - public final int srcPort; - @Field(order = 1, type = Type.U16) - public final int dstPort; - @Field(order = 2, type = Type.U32) - public final long seq; - @Field(order = 3, type = Type.U32) - public final long ack; - @Field(order = 4, type = Type.S16) - // data Offset (4 bits), reserved (6 bits), control bits (6 bits) - // TODO: update with bitfields once class Struct supports it - public final short dataOffsetAndControlBits; - @Field(order = 5, type = Type.U16) - public final int window; - @Field(order = 6, type = Type.S16) - public final short checksum; - @Field(order = 7, type = Type.U16) - public final int urgentPointer; - - public TcpHeader(final int srcPort, final int dstPort, final long seq, final long ack, - final short dataOffsetAndControlBits, final int window, final short checksum, - final int urgentPointer) { - this.srcPort = srcPort; - this.dstPort = dstPort; - this.seq = seq; - this.ack = ack; - this.dataOffsetAndControlBits = dataOffsetAndControlBits; - this.window = window; - this.checksum = checksum; - this.urgentPointer = urgentPointer; - } -} diff --git a/common/device/com/android/net/module/util/structs/UdpHeader.java b/common/device/com/android/net/module/util/structs/UdpHeader.java deleted file mode 100644 index 8b0316bf..00000000 --- a/common/device/com/android/net/module/util/structs/UdpHeader.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2021 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 com.android.net.module.util.structs; - -import com.android.net.module.util.Struct; -import com.android.net.module.util.Struct.Field; -import com.android.net.module.util.Struct.Type; - -/** - * L4 UDP header as per https://tools.ietf.org/html/rfc768. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Source Port | Destination Port | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Length | Checksum | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | data octets ... - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ... - */ -public class UdpHeader extends Struct { - @Field(order = 0, type = Type.U16) - public final int srcPort; - @Field(order = 1, type = Type.U16) - public final int dstPort; - @Field(order = 2, type = Type.U16) - public final int length; - @Field(order = 3, type = Type.S16) - public final short checksum; - - public UdpHeader(final int srcPort, final int dstPort, final int length, - final short checksum) { - this.srcPort = srcPort; - this.dstPort = dstPort; - this.length = length; - this.checksum = checksum; - } -} diff --git a/common/device/com/android/net/module/util/wear/NetPacketHelpers.java b/common/device/com/android/net/module/util/wear/NetPacketHelpers.java deleted file mode 100644 index 341c44be..00000000 --- a/common/device/com/android/net/module/util/wear/NetPacketHelpers.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.wear; - -import com.android.net.module.util.async.ReadableByteBuffer; - -/** - * Implements utilities for decoding parts of TCP/UDP/IP headers. - * - * @hide - */ -final class NetPacketHelpers { - static void encodeNetworkUnsignedInt16(int value, byte[] dst, final int dstPos) { - dst[dstPos] = (byte) ((value >> 8) & 0xFF); - dst[dstPos + 1] = (byte) (value & 0xFF); - } - - static int decodeNetworkUnsignedInt16(byte[] data, final int pos) { - return ((data[pos] & 0xFF) << 8) | (data[pos + 1] & 0xFF); - } - - static int decodeNetworkUnsignedInt16(ReadableByteBuffer data, final int pos) { - return ((data.peek(pos) & 0xFF) << 8) | (data.peek(pos + 1) & 0xFF); - } - - private NetPacketHelpers() {} -} diff --git a/common/device/com/android/net/module/util/wear/PacketFile.java b/common/device/com/android/net/module/util/wear/PacketFile.java deleted file mode 100644 index 7f5ed785..00000000 --- a/common/device/com/android/net/module/util/wear/PacketFile.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.wear; - -/** - * Defines bidirectional file where all transmissions are made as complete packets. - * - * Automatically manages all readability and writeability events in EventManager: - * - When read buffer has more space - asks EventManager to notify on more data - * - When write buffer has more space - asks the user to provide more data - * - When underlying file cannot accept more data - registers EventManager callback - * - * @hide - */ -public interface PacketFile { - /** @hide */ - public enum ErrorCode { - UNEXPECTED_ERROR, - IO_ERROR, - INBOUND_PACKET_TOO_LARGE, - OUTBOUND_PACKET_TOO_LARGE, - } - - /** - * Receives notifications when new data or output space is available. - * - * @hide - */ - public interface Listener { - /** - * Handles the initial part of the stream, which on some systems provides lower-level - * configuration data. - * - * Returns the number of bytes consumed, or zero if the preamble has been fully read. - */ - int onPreambleData(byte[] data, int pos, int len); - - /** Handles one extracted packet. */ - void onInboundPacket(byte[] data, int pos, int len); - - /** Notifies on new data being added to the buffer. */ - void onInboundBuffered(int newByteCount, int totalBufferedSize); - - /** Notifies on data being flushed from output buffer. */ - void onOutboundPacketSpace(); - - /** Notifies on unrecoverable error in the packet processing. */ - void onPacketFileError(ErrorCode error, String message); - } - - /** Requests this file to be closed. */ - void close(); - - /** Permanently disables reading of this file, and clears all buffered data. */ - void shutdownReading(); - - /** Starts or resumes async read operations on this file. */ - void continueReading(); - - /** Returns the number of bytes currently buffered as input. */ - int getInboundBufferSize(); - - /** Returns the number of bytes currently available for buffering for output. */ - int getOutboundFreeSize(); - - /** - * Queues the given data for output. - * Throws runtime exception if there is not enough space. - */ - boolean enqueueOutboundPacket(byte[] data, int pos, int len); -} diff --git a/common/device/com/android/net/module/util/wear/StreamingPacketFile.java b/common/device/com/android/net/module/util/wear/StreamingPacketFile.java deleted file mode 100644 index 52dbee47..00000000 --- a/common/device/com/android/net/module/util/wear/StreamingPacketFile.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2023 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 com.android.net.module.util.wear; - -import com.android.net.module.util.async.BufferedFile; -import com.android.net.module.util.async.EventManager; -import com.android.net.module.util.async.FileHandle; -import com.android.net.module.util.async.Assertions; -import com.android.net.module.util.async.ReadableByteBuffer; - -import java.io.IOException; - -/** - * Implements PacketFile based on a streaming file descriptor. - * - * Packets are delineated using network-order 2-byte length indicators. - * - * @hide - */ -public final class StreamingPacketFile implements PacketFile, BufferedFile.Listener { - private static final int HEADER_SIZE = 2; - - private final EventManager mEventManager; - private final Listener mListener; - private final BufferedFile mFile; - private final int mMaxPacketSize; - private final ReadableByteBuffer mInboundBuffer; - private boolean mIsInPreamble = true; - - private final byte[] mTempPacketReadBuffer; - private final byte[] mTempHeaderWriteBuffer; - - public StreamingPacketFile( - EventManager eventManager, - FileHandle fileHandle, - Listener listener, - int maxPacketSize, - int maxBufferedInboundPackets, - int maxBufferedOutboundPackets) throws IOException { - if (eventManager == null || fileHandle == null || listener == null) { - throw new NullPointerException(); - } - - mEventManager = eventManager; - mListener = listener; - mMaxPacketSize = maxPacketSize; - - final int maxTotalLength = HEADER_SIZE + maxPacketSize; - - mFile = BufferedFile.create(eventManager, fileHandle, this, - maxTotalLength * maxBufferedInboundPackets, - maxTotalLength * maxBufferedOutboundPackets); - mInboundBuffer = mFile.getInboundBuffer(); - - mTempPacketReadBuffer = new byte[maxTotalLength]; - mTempHeaderWriteBuffer = new byte[HEADER_SIZE]; - } - - @Override - public void close() { - mFile.close(); - } - - public BufferedFile getUnderlyingFileForTest() { - return mFile; - } - - @Override - public void shutdownReading() { - mFile.shutdownReading(); - } - - @Override - public void continueReading() { - mFile.continueReading(); - } - - @Override - public int getInboundBufferSize() { - return mInboundBuffer.size(); - } - - @Override - public void onBufferedFileClosed() { - } - - @Override - public void onBufferedFileInboundData(int readByteCount) { - if (mFile.isReadingShutdown()) { - return; - } - - if (readByteCount > 0) { - mListener.onInboundBuffered(readByteCount, mInboundBuffer.size()); - } - - if (extractOnePacket() && !mFile.isReadingShutdown()) { - // There could be more packets already buffered, continue parsing next - // packet even before another read event comes - mEventManager.execute(() -> { - onBufferedFileInboundData(0); - }); - } else { - continueReading(); - } - } - - private boolean extractOnePacket() { - while (mIsInPreamble) { - final int directReadSize = Math.min( - mInboundBuffer.getDirectReadSize(), mTempPacketReadBuffer.length); - if (directReadSize == 0) { - return false; - } - - // Copy for safety, so higher-level callback cannot modify the data. - System.arraycopy(mInboundBuffer.getDirectReadBuffer(), - mInboundBuffer.getDirectReadPos(), mTempPacketReadBuffer, 0, directReadSize); - - final int preambleConsumedBytes = mListener.onPreambleData( - mTempPacketReadBuffer, 0, directReadSize); - if (mFile.isReadingShutdown()) { - return false; // The callback has called shutdownReading(). - } - - if (preambleConsumedBytes == 0) { - mIsInPreamble = false; - break; - } - - mInboundBuffer.accountForDirectRead(preambleConsumedBytes); - } - - final int bufferedSize = mInboundBuffer.size(); - if (bufferedSize < HEADER_SIZE) { - return false; - } - - final int dataLength = NetPacketHelpers.decodeNetworkUnsignedInt16(mInboundBuffer, 0); - if (dataLength > mMaxPacketSize) { - mListener.onPacketFileError( - PacketFile.ErrorCode.INBOUND_PACKET_TOO_LARGE, - "Inbound packet length: " + dataLength); - return false; - } - - final int totalLength = HEADER_SIZE + dataLength; - if (bufferedSize < totalLength) { - return false; - } - - mInboundBuffer.readBytes(mTempPacketReadBuffer, 0, totalLength); - - mListener.onInboundPacket(mTempPacketReadBuffer, HEADER_SIZE, dataLength); - return true; - } - - @Override - public int getOutboundFreeSize() { - final int freeSize = mFile.getOutboundBufferFreeSize(); - return (freeSize > HEADER_SIZE ? freeSize - HEADER_SIZE : 0); - } - - @Override - public boolean enqueueOutboundPacket(byte[] buffer, int pos, int len) { - Assertions.throwsIfOutOfBounds(buffer, pos, len); - - if (len == 0) { - return true; - } - - if (len > mMaxPacketSize) { - mListener.onPacketFileError( - PacketFile.ErrorCode.OUTBOUND_PACKET_TOO_LARGE, - "Outbound packet length: " + len); - return false; - } - - NetPacketHelpers.encodeNetworkUnsignedInt16(len, mTempHeaderWriteBuffer, 0); - - mFile.enqueueOutboundData( - mTempHeaderWriteBuffer, 0, mTempHeaderWriteBuffer.length, - buffer, pos, len); - return true; - } - - @Override - public void onBufferedFileOutboundSpace() { - mListener.onOutboundPacketSpace(); - } - - @Override - public void onBufferedFileIoError(String message) { - mListener.onPacketFileError(PacketFile.ErrorCode.IO_ERROR, message); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("maxPacket="); - sb.append(mMaxPacketSize); - sb.append(", file={"); - sb.append(mFile); - sb.append("}"); - return sb.toString(); - } -} |