Loading core/java/android/net/netlink/NetlinkConstants.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.system.OsConstants; import com.android.internal.util.HexDump; import java.nio.ByteBuffer; /** * Various constants and static helper methods for netlink communications. * * Values taken from: * * <linux_src>/include/uapi/linux/netlink.h * <linux_src>/include/uapi/linux/rtnetlink.h * * @hide */ public class NetlinkConstants { private NetlinkConstants() {} public static final int NLA_ALIGNTO = 4; public static final int alignedLengthOf(short length) { final int intLength = (int) length & 0xffff; return alignedLengthOf(intLength); } public static final int alignedLengthOf(int length) { if (length <= 0) { return 0; } return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); } 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"; } return String.valueOf(family); } public static String hexify(byte[] bytes) { if (bytes == null) { return "(null)"; } return HexDump.toHexString(bytes); } public static String hexify(ByteBuffer buffer) { if (buffer == null) { return "(null)"; } return HexDump.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; public static String stringForNlMsgType(short nlm_type) { switch (nlm_type) { case NLMSG_NOOP: return "NLMSG_NOOP"; case NLMSG_ERROR: return "NLMSG_ERROR"; case NLMSG_DONE: return "NLMSG_DONE"; case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; 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(nlm_type); } } } core/java/android/net/netlink/NetlinkErrorMessage.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.StructNlMsgHdr; import android.net.netlink.NetlinkMessage; import android.util.Log; import java.nio.ByteBuffer; /** * A NetlinkMessage subclass for netlink error messages. * * @hide */ public class NetlinkErrorMessage extends NetlinkMessage { public static NetlinkErrorMessage parse(StructNlMsgHdr header, 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(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()) + "} " + "}"; } } core/java/android/net/netlink/NetlinkMessage.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNlAttr; import android.net.netlink.StructNlMsgHdr; import android.util.Log; 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 final static String TAG = "NetlinkMessage"; public static NetlinkMessage parse(ByteBuffer byteBuffer) { final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); if (nlmsghdr == null) { return null; } int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); payloadLength -= 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; } switch (nlmsghdr.nlmsg_type) { //case NetlinkConstants.NLMSG_NOOP: case NetlinkConstants.NLMSG_ERROR: return (NetlinkMessage) NetlinkErrorMessage.parse(byteBuffer); case NetlinkConstants.NLMSG_DONE: byteBuffer.position(byteBuffer.position() + payloadLength); return new NetlinkMessage(nlmsghdr); //case NetlinkConstants.NLMSG_OVERRUN: case NetlinkConstants.RTM_NEWNEIGH: case NetlinkConstants.RTM_DELNEIGH: case NetlinkConstants.RTM_GETNEIGH: return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); default: if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { // Netlink control message. Just parse the header for now, // pretending the whole message was consumed. byteBuffer.position(byteBuffer.position() + payloadLength); return new NetlinkMessage(nlmsghdr); } return null; } } protected StructNlMsgHdr mHeader; public NetlinkMessage(StructNlMsgHdr nlmsghdr) { mHeader = nlmsghdr; } public StructNlMsgHdr getHeader() { return mHeader; } @Override public String toString() { return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}"; } } core/java/android/net/netlink/NetlinkSocket.java 0 → 100644 +169 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.system.StructTimeval; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.Closeable; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * NetlinkSocket * * A small wrapper class to assist with AF_NETLINK socket operations. * * @hide */ public class NetlinkSocket implements Closeable { private static final String TAG = "NetlinkSocket"; private static final int SOCKET_RECV_BUFSIZE = 64 * 1024; private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; final private FileDescriptor mDescriptor; private NetlinkSocketAddress mAddr; private long mLastRecvTimeoutMs; private long mLastSendTimeoutMs; public NetlinkSocket(int nlProto) throws ErrnoException { mDescriptor = Os.socket( OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto); Libcore.os.setsockoptInt( mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE); } public NetlinkSocketAddress getLocalAddress() throws ErrnoException { return (NetlinkSocketAddress) Os.getsockname(mDescriptor); } public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException { Os.bind(mDescriptor, (SocketAddress)localAddr); } public void connectTo(NetlinkSocketAddress peerAddr) throws ErrnoException, SocketException { Os.connect(mDescriptor, (SocketAddress) peerAddr); } public void connectToKernel() throws ErrnoException, SocketException { connectTo(new NetlinkSocketAddress(0, 0)); } /** * Wait indefinitely (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage() throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, 0); } /** * Wait up to |timeoutMs| (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs); } private 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 ByteBuffer recvMessage(int bufsize, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastRecvTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastRecvTimeoutMs = timeoutMs; } } ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); int length = Os.read(mDescriptor, 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 blocks until completion or an error occurs. */ public boolean sendMessage(byte[] bytes, int offset, int count) throws ErrnoException, InterruptedIOException { return sendMessage(bytes, offset, count, 0); } /** * Send a message to a peer to which this socket has previously connected, * waiting at most |timeoutMs| milliseconds for the send to complete. * * Multi-threaded calls with different timeouts will cause unexpected results. */ public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastSendTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastSendTimeoutMs = timeoutMs; } } return (count == Os.write(mDescriptor, bytes, offset, count)); } @Override public void close() { IoUtils.closeQuietly(mDescriptor); } } core/java/android/net/netlink/RtNetlinkNeighborMessage.java 0 → 100644 +181 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.StructNdaCacheInfo; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlAttr; import android.net.netlink.StructNlMsgHdr; import android.net.netlink.NetlinkMessage; import android.util.Log; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A NetlinkMessage subclass for netlink error 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; private static StructNlAttr findNextAttrOfType(short attrType, 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 static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, 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 = findNextAttrOfType(NDA_DST, byteBuffer); if (nlAttr != null) { neighMsg.mDestination = nlAttr.getValueAsInetAddress(); } byteBuffer.position(baseOffset); nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer); if (nlAttr != null) { neighMsg.mLinkLayerAddr = nlAttr.nla_value; } byteBuffer.position(baseOffset); nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer); if (nlAttr != null) { neighMsg.mNumProbes = nlAttr.getValueAsInt(0); } byteBuffer.position(baseOffset); nlAttr = 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 = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP; nlmsghdr.nlmsg_seq = seqNo; nlmsghdr.pack(byteBuffer); final StructNdMsg ndmsg = new StructNdMsg(); ndmsg.pack(byteBuffer); return bytes; } private StructNdMsg mNdmsg; private InetAddress mDestination; private byte[] mLinkLayerAddr; private int mNumProbes; private StructNdaCacheInfo mCacheInfo; private RtNetlinkNeighborMessage(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; } @Override public String toString() { final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); return "RtNetlinkNeighborMessage{ " + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " + "destination{" + ipLiteral + "} " + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " + "probes{" + mNumProbes + "} " + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " + "}"; } } Loading
core/java/android/net/netlink/NetlinkConstants.java 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.system.OsConstants; import com.android.internal.util.HexDump; import java.nio.ByteBuffer; /** * Various constants and static helper methods for netlink communications. * * Values taken from: * * <linux_src>/include/uapi/linux/netlink.h * <linux_src>/include/uapi/linux/rtnetlink.h * * @hide */ public class NetlinkConstants { private NetlinkConstants() {} public static final int NLA_ALIGNTO = 4; public static final int alignedLengthOf(short length) { final int intLength = (int) length & 0xffff; return alignedLengthOf(intLength); } public static final int alignedLengthOf(int length) { if (length <= 0) { return 0; } return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); } 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"; } return String.valueOf(family); } public static String hexify(byte[] bytes) { if (bytes == null) { return "(null)"; } return HexDump.toHexString(bytes); } public static String hexify(ByteBuffer buffer) { if (buffer == null) { return "(null)"; } return HexDump.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; public static String stringForNlMsgType(short nlm_type) { switch (nlm_type) { case NLMSG_NOOP: return "NLMSG_NOOP"; case NLMSG_ERROR: return "NLMSG_ERROR"; case NLMSG_DONE: return "NLMSG_DONE"; case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; 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(nlm_type); } } }
core/java/android/net/netlink/NetlinkErrorMessage.java 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.StructNlMsgHdr; import android.net.netlink.NetlinkMessage; import android.util.Log; import java.nio.ByteBuffer; /** * A NetlinkMessage subclass for netlink error messages. * * @hide */ public class NetlinkErrorMessage extends NetlinkMessage { public static NetlinkErrorMessage parse(StructNlMsgHdr header, 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(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()) + "} " + "}"; } }
core/java/android/net/netlink/NetlinkMessage.java 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkErrorMessage; import android.net.netlink.RtNetlinkNeighborMessage; import android.net.netlink.StructNlAttr; import android.net.netlink.StructNlMsgHdr; import android.util.Log; 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 final static String TAG = "NetlinkMessage"; public static NetlinkMessage parse(ByteBuffer byteBuffer) { final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); if (nlmsghdr == null) { return null; } int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); payloadLength -= 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; } switch (nlmsghdr.nlmsg_type) { //case NetlinkConstants.NLMSG_NOOP: case NetlinkConstants.NLMSG_ERROR: return (NetlinkMessage) NetlinkErrorMessage.parse(byteBuffer); case NetlinkConstants.NLMSG_DONE: byteBuffer.position(byteBuffer.position() + payloadLength); return new NetlinkMessage(nlmsghdr); //case NetlinkConstants.NLMSG_OVERRUN: case NetlinkConstants.RTM_NEWNEIGH: case NetlinkConstants.RTM_DELNEIGH: case NetlinkConstants.RTM_GETNEIGH: return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); default: if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { // Netlink control message. Just parse the header for now, // pretending the whole message was consumed. byteBuffer.position(byteBuffer.position() + payloadLength); return new NetlinkMessage(nlmsghdr); } return null; } } protected StructNlMsgHdr mHeader; public NetlinkMessage(StructNlMsgHdr nlmsghdr) { mHeader = nlmsghdr; } public StructNlMsgHdr getHeader() { return mHeader; } @Override public String toString() { return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}"; } }
core/java/android/net/netlink/NetlinkSocket.java 0 → 100644 +169 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.system.ErrnoException; import android.system.NetlinkSocketAddress; import android.system.Os; import android.system.OsConstants; import android.system.StructTimeval; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.Closeable; import java.io.FileDescriptor; import java.io.InterruptedIOException; import java.net.SocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * NetlinkSocket * * A small wrapper class to assist with AF_NETLINK socket operations. * * @hide */ public class NetlinkSocket implements Closeable { private static final String TAG = "NetlinkSocket"; private static final int SOCKET_RECV_BUFSIZE = 64 * 1024; private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; final private FileDescriptor mDescriptor; private NetlinkSocketAddress mAddr; private long mLastRecvTimeoutMs; private long mLastSendTimeoutMs; public NetlinkSocket(int nlProto) throws ErrnoException { mDescriptor = Os.socket( OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto); Libcore.os.setsockoptInt( mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE); } public NetlinkSocketAddress getLocalAddress() throws ErrnoException { return (NetlinkSocketAddress) Os.getsockname(mDescriptor); } public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException { Os.bind(mDescriptor, (SocketAddress)localAddr); } public void connectTo(NetlinkSocketAddress peerAddr) throws ErrnoException, SocketException { Os.connect(mDescriptor, (SocketAddress) peerAddr); } public void connectToKernel() throws ErrnoException, SocketException { connectTo(new NetlinkSocketAddress(0, 0)); } /** * Wait indefinitely (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage() throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, 0); } /** * Wait up to |timeoutMs| (or until underlying socket error) for a * netlink message of at most DEFAULT_RECV_BUFSIZE size. */ public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException { return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs); } private 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 ByteBuffer recvMessage(int bufsize, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastRecvTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastRecvTimeoutMs = timeoutMs; } } ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); int length = Os.read(mDescriptor, 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 blocks until completion or an error occurs. */ public boolean sendMessage(byte[] bytes, int offset, int count) throws ErrnoException, InterruptedIOException { return sendMessage(bytes, offset, count, 0); } /** * Send a message to a peer to which this socket has previously connected, * waiting at most |timeoutMs| milliseconds for the send to complete. * * Multi-threaded calls with different timeouts will cause unexpected results. */ public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs) throws ErrnoException, IllegalArgumentException, InterruptedIOException { checkTimeout(timeoutMs); synchronized (mDescriptor) { if (mLastSendTimeoutMs != timeoutMs) { Os.setsockoptTimeval(mDescriptor, OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); mLastSendTimeoutMs = timeoutMs; } } return (count == Os.write(mDescriptor, bytes, offset, count)); } @Override public void close() { IoUtils.closeQuietly(mDescriptor); } }
core/java/android/net/netlink/RtNetlinkNeighborMessage.java 0 → 100644 +181 −0 Original line number Diff line number Diff line /* * 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 android.net.netlink; import android.net.netlink.StructNdaCacheInfo; import android.net.netlink.StructNdMsg; import android.net.netlink.StructNlAttr; import android.net.netlink.StructNlMsgHdr; import android.net.netlink.NetlinkMessage; import android.util.Log; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; /** * A NetlinkMessage subclass for netlink error 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; private static StructNlAttr findNextAttrOfType(short attrType, 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 static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, 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 = findNextAttrOfType(NDA_DST, byteBuffer); if (nlAttr != null) { neighMsg.mDestination = nlAttr.getValueAsInetAddress(); } byteBuffer.position(baseOffset); nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer); if (nlAttr != null) { neighMsg.mLinkLayerAddr = nlAttr.nla_value; } byteBuffer.position(baseOffset); nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer); if (nlAttr != null) { neighMsg.mNumProbes = nlAttr.getValueAsInt(0); } byteBuffer.position(baseOffset); nlAttr = 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 = StructNlMsgHdr.NLM_F_REQUEST|StructNlMsgHdr.NLM_F_DUMP; nlmsghdr.nlmsg_seq = seqNo; nlmsghdr.pack(byteBuffer); final StructNdMsg ndmsg = new StructNdMsg(); ndmsg.pack(byteBuffer); return bytes; } private StructNdMsg mNdmsg; private InetAddress mDestination; private byte[] mLinkLayerAddr; private int mNumProbes; private StructNdaCacheInfo mCacheInfo; private RtNetlinkNeighborMessage(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; } @Override public String toString() { final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); return "RtNetlinkNeighborMessage{ " + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " + "destination{" + ipLiteral + "} " + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " + "probes{" + mNumProbes + "} " + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " + "}"; } }