/* * 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 + "} " + "}"; } }