Merge "Parse IFLA_INET6_FLAGS attr from the RTM_NEWLINK message." into main

This commit is contained in:
Treehugger Robot 2025-09-11 18:53:12 -07:00 • committed by Android (Google) Code Review
commit 0c8a65ff9a
2 changed files with 98 additions and 6 deletions

View file

@ -16,6 +16,7 @@
package com.android.net.module.util.netlink;
import static android.system.OsConstants.AF_INET6;
import static android.system.OsConstants.AF_UNSPEC;
import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN;
@ -53,6 +54,7 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
public static final short IFLA_MTU = 4;
public static final short IFLA_INET6_ADDR_GEN_MODE = 8;
public static final short IFLA_AF_SPEC = 26;
public static final short IFLA_INET6_FLAGS = 1;
public static final short IN6_ADDR_GEN_MODE_NONE = 1;
@ -60,6 +62,8 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
private static final int IFNAMSIZ = 16;
// The default value of MTU, which means the MTU is unspecified.
private static final int DEFAULT_MTU = 0;
// The default value of IPv6 link attribute flags.
private static final int DEFAULT_IFLA_INET6_FLAGS = 0;
@NonNull
private final StructIfinfoMsg mIfinfomsg;
@ -69,6 +73,24 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
@Nullable
private final String mInterfaceName;
// IPv6 operational flags for the interface, from the IFLA_INET6_FLAGS netlink attribute.
// also see inet6_dev.if_flags in if_inet6.h
private final int mInet6Flags;
/**
* Creates an {@link RtNetlinkLinkMessage} instance.
*
* @return A new {@link RtNetlinkLinkMessage} instance, or {@code null} if the input arguments
* are invalid.
*/
@Nullable
public static RtNetlinkLinkMessage build(@NonNull StructNlMsgHdr nlmsghdr,
@NonNull StructIfinfoMsg ifinfomsg, int mtu, @Nullable MacAddress hardwareAddress,
@Nullable String interfaceName) {
return RtNetlinkLinkMessage.build(nlmsghdr, ifinfomsg, mtu, hardwareAddress, interfaceName,
DEFAULT_IFLA_INET6_FLAGS);
}
/**
* Creates an {@link RtNetlinkLinkMessage} instance.
*
@ -80,13 +102,14 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
* @param mtu The Maximum Transmission Unit (MTU) value for the link.
* @param hardwareAddress The hardware address (MAC address) of the link. May be {@code null}.
* @param interfaceName The name of the interface. May be {@code null}.
* @param inet6Flags IPv6 operational flags for the interface.
* @return A new {@link RtNetlinkLinkMessage} instance, or {@code null} if the input arguments
* are invalid.
*/
@Nullable
public static RtNetlinkLinkMessage build(@NonNull StructNlMsgHdr nlmsghdr,
@NonNull StructIfinfoMsg ifinfomsg, int mtu, @Nullable MacAddress hardwareAddress,
@Nullable String interfaceName) {
@Nullable String interfaceName, int inet6Flags) {
if (mtu < 0) {
return null;
}
@ -96,17 +119,19 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
}
nlmsghdr.nlmsg_len = calculateMessageLength(mtu, hardwareAddress, interfaceName);
return new RtNetlinkLinkMessage(nlmsghdr, ifinfomsg, mtu, hardwareAddress, interfaceName);
return new RtNetlinkLinkMessage(nlmsghdr, ifinfomsg, mtu, hardwareAddress, interfaceName,
inet6Flags);
}
private RtNetlinkLinkMessage(@NonNull StructNlMsgHdr nlmsghdr,
@NonNull StructIfinfoMsg ifinfomsg, int mtu, @Nullable MacAddress hardwareAddress,
@Nullable String interfaceName) {
@Nullable String interfaceName, int inet6Flags) {
super(nlmsghdr);
mIfinfomsg = ifinfomsg;
mMtu = mtu;
mHardwareAddress = hardwareAddress;
mInterfaceName = interfaceName;
mInet6Flags = inet6Flags;
}
public int getMtu() {
@ -128,6 +153,10 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
return mInterfaceName;
}
public int getInet6Flags() {
return mInet6Flags;
}
/**
* Parse rtnetlink link message from {@link ByteBuffer}. This method must be called with a
* ByteBuffer that contains exactly one netlink message.
@ -171,7 +200,42 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
return null;
}
return new RtNetlinkLinkMessage(header, ifinfoMsg, mtu, hardwareAddress, interfaceName);
/*
* IFLA_AF_SPEC:
* Contains nested attributes for address family specific attributes.
* Each address family may create a attribute with the address family
* number as type and create its own attribute structure in it.
*
* Example:
* [IFLA_AF_SPEC] = {
* [AF_INET] = {
* [IFLA_INET_CONF] = ...,
* },
* [AF_INET6] = {
* [IFLA_INET6_FLAGS] = ...,
* [IFLA_INET6_CONF] = ...,
* }
* }
*/
int inet6Flags = DEFAULT_IFLA_INET6_FLAGS;
byteBuffer.position(baseOffset);
nlAttr = StructNlAttr.findNextAttrOfType(IFLA_AF_SPEC, byteBuffer);
if (nlAttr != null) {
final StructNlAttr ipv6ConfigAttrs = StructNlAttr.findNextAttrOfType(
(short) AF_INET6,
nlAttr.getValueAsByteBuffer());
if (ipv6ConfigAttrs != null) {
final StructNlAttr inet6FlagsAttr = StructNlAttr.findNextAttrOfType(
IFLA_INET6_FLAGS,
ipv6ConfigAttrs.getValueAsByteBuffer());
if (inet6FlagsAttr != null) {
inet6Flags = inet6FlagsAttr.getValueAsInt(DEFAULT_IFLA_INET6_FLAGS);
}
}
}
return new RtNetlinkLinkMessage(header, ifinfoMsg, mtu, hardwareAddress, interfaceName,
inet6Flags);
}
/**
@ -368,7 +432,8 @@ public class RtNetlinkLinkMessage extends NetlinkMessage {
+ "Ifinfomsg{" + mIfinfomsg + "}, "
+ "Hardware Address{" + mHardwareAddress + "}, "
+ "MTU{" + mMtu + "}, "
+ "Ifname{" + mInterfaceName + "} "
+ "Ifname{" + mInterfaceName + "}, "
+ "IFLA_INET6_FLAGS{" + mInet6Flags + "} "
+ "}";
}
}

View file

@ -332,7 +332,8 @@ public class RtNetlinkLinkMessageTest {
+ "Ifinfomsg{"
+ "family: 0, type: 1, index: 30, flags: 4098, change: 0}, "
+ "Hardware Address{92:c3:e3:c9:37:4e}, " + "MTU{1500}, "
+ "Ifname{wlan0} "
+ "Ifname{wlan0}, "
+ "IFLA_INET6_FLAGS{0} "
+ "}";
assertEquals(expected, linkMsg.toString());
}
@ -358,4 +359,30 @@ public class RtNetlinkLinkMessageTest {
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
assertNull(msg);
}
@Test
public void testParseRtNetlinkMessageWithMOrOBit() {
final String msgBytes =
"7C000000100000000100000000000000" // nlmsghdr (16 bytes)
+ "000001000200000043100000FFFFFFFF" // ifinfomsg (16 bytes)
+ "090003006574683000000000" // IFLA_IFNAME (12 bytes)
+ "50001A00" // IFLA_AF_SPEC (84 bytes)
+ "1C000200" // Nested AF_INET (28 bytes)
+ "18000100" // Nested IFLA_INET_CONF (24 bytes)
+ "0000000000000000000000000000000000000000" // 20 bytes of dummy payload
+ "30000A00" // Nested AF_INET6 (48 bytes)
+ "08000100C0000000" // Nested IFLA_INET6_FLAGS (8 bytes): M=1,O=1
+ "24000600" // Nested IFLA_INET6_CONF (36 bytes)
+ "00000000000000000000000000000000" // 16 bytes of dummy payload
+ "00000000000000000000000000000000"; // 16 bytes of dummy payload
final ByteBuffer byteBuffer = toByteBuffer(msgBytes);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing.
final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer, NETLINK_ROUTE);
assertNotNull(msg);
assertTrue(msg instanceof RtNetlinkLinkMessage);
final RtNetlinkLinkMessage linkMsg = (RtNetlinkLinkMessage) msg;
final int flags = linkMsg.getInet6Flags();
assertEquals(0xC0, flags);
}
}