diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/moduleutils/Android.bp | 1 | ||||
-rw-r--r-- | common/moduleutils/src/android/net/ip/IpNeighborMonitor.java | 87 | ||||
-rw-r--r-- | common/moduleutils/src/android/net/ip/NetlinkMonitor.java | 141 |
3 files changed, 149 insertions, 80 deletions
diff --git a/common/moduleutils/Android.bp b/common/moduleutils/Android.bp index f32f8d8..93ee00c 100644 --- a/common/moduleutils/Android.bp +++ b/common/moduleutils/Android.bp @@ -53,6 +53,7 @@ filegroup { srcs: [ "src/android/net/ip/InterfaceController.java", "src/android/net/ip/IpNeighborMonitor.java", + "src/android/net/ip/NetlinkMonitor.java", "src/android/net/netlink/*.java", "src/android/net/shared/NetdUtils.java", "src/android/net/shared/RouteUtils.java", diff --git a/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java b/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java index d6706d4..18a9f90 100644 --- a/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java +++ b/common/moduleutils/src/android/net/ip/IpNeighborMonitor.java @@ -19,35 +19,20 @@ package android.net.ip; import static android.net.netlink.NetlinkConstants.RTM_DELNEIGH; import static android.net.netlink.NetlinkConstants.hexify; import static android.net.netlink.NetlinkConstants.stringForNlMsgType; -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; -import static android.system.OsConstants.AF_NETLINK; import static android.system.OsConstants.NETLINK_ROUTE; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOCK_NONBLOCK; import android.net.MacAddress; -import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.NetlinkMessage; import android.net.netlink.NetlinkSocket; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNdMsg; -import android.net.util.PacketReader; import android.net.util.SharedLog; -import android.net.util.SocketUtils; import android.os.Handler; -import android.os.SystemClock; import android.system.ErrnoException; -import android.system.Os; import android.system.OsConstants; import android.util.Log; -import java.io.FileDescriptor; -import java.io.IOException; import java.net.InetAddress; -import java.net.SocketAddress; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.StringJoiner; @@ -61,7 +46,7 @@ import java.util.StringJoiner; * * @hide */ -public class IpNeighborMonitor extends PacketReader { +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; @@ -129,85 +114,27 @@ public class IpNeighborMonitor extends PacketReader { } } - // TODO: move NetworkStackUtils.closeSocketQuietly to somewhere accessible to this file. - private void closeSocketQuietly(FileDescriptor fd) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException ignored) { - } - } - public interface NeighborEventConsumer { // Every neighbor event received on the netlink socket is passed in // here. Subclasses should filter for events of interest. public void accept(NeighborEvent event); } - private final SharedLog mLog; private final NeighborEventConsumer mConsumer; public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) { - super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); - mLog = log.forSubComponent(TAG); + super(h, log, TAG, NETLINK_ROUTE, OsConstants.RTMGRP_NEIGH); mConsumer = (cb != null) ? cb : (event) -> { /* discard */ }; } @Override - protected FileDescriptor createFd() { - FileDescriptor fd = null; - - try { - fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, NETLINK_ROUTE); - Os.bind(fd, makeNetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)); - NetlinkSocket.connectToKernel(fd); - - if (VDBG) { - final SocketAddress nlAddr = Os.getsockname(fd); - Log.d(TAG, "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()); - - parseNetlinkMessageBuffer(byteBuffer, whenMs); - } - - private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) { - while (byteBuffer.remaining() > 0) { - final int position = byteBuffer.position(); - final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); - 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; - } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { - mLog.i("non-rtnetlink neighbor msg: " + nlMsg); - continue; - } - - evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs); + public void processNetlinkMessage(NetlinkMessage nlMsg, final long whenMs) { + if (!(nlMsg instanceof RtNetlinkNeighborMessage)) { + mLog.e("non-rtnetlink neighbor msg: " + nlMsg); + return; } - } - private void evaluateRtNetlinkNeighborMessage( - RtNetlinkNeighborMessage neighMsg, long whenMs) { + final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) nlMsg; final short msgType = neighMsg.getHeader().nlmsg_type; final StructNdMsg ndMsg = neighMsg.getNdHeader(); if (ndMsg == null) { diff --git a/common/moduleutils/src/android/net/ip/NetlinkMonitor.java b/common/moduleutils/src/android/net/ip/NetlinkMonitor.java new file mode 100644 index 0000000..806f3ef --- /dev/null +++ b/common/moduleutils/src/android/net/ip/NetlinkMonitor.java @@ -0,0 +1,141 @@ +/* + * 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 android.net.ip; + +import static android.net.netlink.NetlinkConstants.hexify; +import static android.net.util.SocketUtils.makeNetlinkSocketAddress; +import static android.system.OsConstants.AF_NETLINK; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; + +import android.annotation.NonNull; +import android.net.netlink.NetlinkErrorMessage; +import android.net.netlink.NetlinkMessage; +import android.net.netlink.NetlinkSocket; +import android.net.util.PacketReader; +import android.net.util.SharedLog; +import android.net.util.SocketUtils; +import android.os.Handler; +import android.os.SystemClock; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; +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. + */ +public class NetlinkMonitor extends PacketReader { + protected final SharedLog mLog; + protected final String mTag; + private final int mFamily; + private final int mBindGroups; + + private static final boolean DBG = false; + + /** + * 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. + */ + public NetlinkMonitor(@NonNull Handler h, @NonNull SharedLog log, @NonNull String tag, + int family, int bindGroups) { + super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE); + mLog = log.forSubComponent(tag); + mTag = tag; + mFamily = family; + mBindGroups = bindGroups; + } + + @Override + protected FileDescriptor createFd() { + FileDescriptor fd = null; + + try { + fd = Os.socket(AF_NETLINK, SOCK_DGRAM | SOCK_NONBLOCK, mFamily); + Os.bind(fd, makeNetlinkSocketAddress(0, mBindGroups)); + NetlinkSocket.connectToKernel(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) { + final int position = byteBuffer.position(); + final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer); + 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); + } + } + + // TODO: move NetworkStackUtils to frameworks/libs/net for NetworkStackUtils#closeSocketQuietly. + private void closeSocketQuietly(FileDescriptor fd) { + try { + SocketUtils.closeSocket(fd); + } catch (IOException ignored) { + } + } + + /** + * 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) { } +} |