| /* |
| * 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.system.OsConstants; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.VisibleForTesting; |
| |
| import com.android.net.module.util.HexDump; |
| |
| import java.net.InetAddress; |
| import java.nio.ByteBuffer; |
| |
| /** |
| * 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; |
| |
| private RtNetlinkAddressMessage(@NonNull StructNlMsgHdr header) { |
| super(header); |
| mIfaddrmsg = null; |
| mIpAddress = null; |
| mIfacacheInfo = null; |
| mFlags = 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); |
| } |
| |
| @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) + "} " |
| + "}"; |
| } |
| } |