diff options
author | 2024-08-03 19:57:58 +0000 | |
---|---|---|
committer | 2024-08-03 19:57:58 +0000 | |
commit | e4a5d144d16eca6501ba948b2371fec32a3f5db0 (patch) | |
tree | d645cdb555b6f72f6d25564c1ad266fa872a4816 /service | |
parent | a776d6fe1b8e6f45c7dfc6c52c963e8e13ff2aec (diff) | |
parent | 41540041f1b96b0edda9c462c746bf7e64414c31 (diff) |
Retrieve multicast groups information during am: 41540041f1
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Wifi/+/3162692
Change-Id: I69cbc29c10fa5c045e161ccc64ae898000b34855
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'service')
6 files changed, 167 insertions, 1 deletions
diff --git a/service/java/com/android/server/wifi/nl80211/GenericNetlinkMsg.java b/service/java/com/android/server/wifi/nl80211/GenericNetlinkMsg.java index 82a788777d..b68ee79e96 100644 --- a/service/java/com/android/server/wifi/nl80211/GenericNetlinkMsg.java +++ b/service/java/com/android/server/wifi/nl80211/GenericNetlinkMsg.java @@ -110,6 +110,22 @@ public class GenericNetlinkMsg { } /** + * Retrieve the inner attributes from a nested attribute. + * + * @param outerAttribute containing nested inner attributes + * @return Inner attributes if valid, or null otherwise. + * Attributes will be represented as an (attributeId -> attribute) map. + */ + public static @Nullable Map<Short, StructNlAttr> getInnerNestedAttributes( + @NonNull StructNlAttr outerAttribute) { + if (outerAttribute == null) return null; + // Outer attribute's payload is a byte buffer containing additional attributes + ByteBuffer innerBytes = outerAttribute.getValueAsByteBuffer(); + if (innerBytes == null) return null; + return parseAttributesToMap(innerBytes, innerBytes.remaining()); + } + + /** * Check that this message contains the expected fields. */ public boolean verifyFields(short command, short... attributeIds) { diff --git a/service/java/com/android/server/wifi/nl80211/NetlinkConstants.java b/service/java/com/android/server/wifi/nl80211/NetlinkConstants.java index 365616e257..2e56c2dc79 100644 --- a/service/java/com/android/server/wifi/nl80211/NetlinkConstants.java +++ b/service/java/com/android/server/wifi/nl80211/NetlinkConstants.java @@ -34,6 +34,14 @@ public class NetlinkConstants { public static final short CTRL_ATTR_FAMILY_ID = 1; public static final short CTRL_ATTR_FAMILY_NAME = 2; + public static final short CTRL_ATTR_MCAST_GRP_NAME = 1; + public static final short CTRL_ATTR_MCAST_GRP_ID = 2; + + public static final short CTRL_ATTR_MCAST_GROUPS = 7; + // Nl80211 strings for initialization. See kernel/uapi/linux/nl80211.h public static final String NL80211_GENL_NAME = "nl80211"; + public static final String NL80211_MULTICAST_GROUP_SCAN = "scan"; + public static final String NL80211_MULTICAST_GROUP_REG = "regulatory"; + public static final String NL80211_MULTICAST_GROUP_MLME = "mlme"; } diff --git a/service/java/com/android/server/wifi/nl80211/Nl80211Proxy.java b/service/java/com/android/server/wifi/nl80211/Nl80211Proxy.java index 78a69c82c4..02ccd5a28f 100644 --- a/service/java/com/android/server/wifi/nl80211/Nl80211Proxy.java +++ b/service/java/com/android/server/wifi/nl80211/Nl80211Proxy.java @@ -18,17 +18,24 @@ package com.android.server.wifi.nl80211; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_FAMILY_ID; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_FAMILY_NAME; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GROUPS; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GRP_ID; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GRP_NAME; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_CMD_GETFAMILY; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_CMD_NEWFAMILY; import static com.android.server.wifi.nl80211.NetlinkConstants.GENL_ID_CTRL; import static com.android.server.wifi.nl80211.NetlinkConstants.NETLINK_GENERIC; import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_GENL_NAME; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_MLME; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_REG; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_SCAN; import android.annotation.NonNull; import android.annotation.Nullable; import android.system.ErrnoException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.netlink.NetlinkUtils; import com.android.net.module.util.netlink.StructNlAttr; import com.android.net.module.util.netlink.StructNlMsgHdr; @@ -38,7 +45,9 @@ import java.io.InterruptedIOException; import java.net.SocketException; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Wrapper around Nl80211 functionality. Allows sending and receiving Nl80211 messages. @@ -46,11 +55,18 @@ import java.util.List; public class Nl80211Proxy { private static final String TAG = "Nl80211Proxy"; + private static final String[] sRequiredMulticastGroups = new String[]{ + NL80211_MULTICAST_GROUP_SCAN, + NL80211_MULTICAST_GROUP_REG, + NL80211_MULTICAST_GROUP_MLME}; + private boolean mIsInitialized; private FileDescriptor mNetlinkFd; private short mNl80211FamilyId; private int mSequenceNumber; + private Map<String, Integer> mMulticastGroups = new HashMap<>(); + public Nl80211Proxy() {} private int getSequenceNumber() { @@ -178,7 +194,8 @@ public class Nl80211Proxy { request.addAttribute(new StructNlAttr(CTRL_ATTR_FAMILY_NAME, NL80211_GENL_NAME)); GenericNetlinkMsg response = sendMessageAndReceiveResponse(request); - if (response == null || !response.verifyFields(CTRL_CMD_NEWFAMILY, CTRL_ATTR_FAMILY_ID)) { + if (response == null || !response.verifyFields(CTRL_CMD_NEWFAMILY, + CTRL_ATTR_FAMILY_ID, CTRL_ATTR_MCAST_GROUPS)) { Log.e(TAG, "Unable to request family information"); return false; } @@ -189,10 +206,62 @@ public class Nl80211Proxy { return false; } mNl80211FamilyId = familyId; + + Map<String, Integer> multicastGroups = + parseMulticastGroupsAttribute(response.getAttribute(CTRL_ATTR_MCAST_GROUPS)); + for (String groupName : sRequiredMulticastGroups) { + if (!multicastGroups.containsKey(groupName)) { + Log.e(TAG, "Missing required multicast group. Retrieved=" + multicastGroups); + return false; + } + } + mMulticastGroups = multicastGroups; + + Log.i(TAG, "Successfully retrieved Nl80211 family information"); return true; } /** + * Parse the nested multicast groups attribute. + * + * Expected structure is: + * - ID=CTRL_ATTR_MCAST_GROUPS, VAL={nested} --- + * - ID=1, VAL={nested} --- | + * - ID=CTRL_ATTR_MCAST_GRP_NAME, VAL={string} | groupAttr | + * - ID=CTRL_ATTR_MCAST_GRP_ID, VAL={int} --- | rootAttr + * - ID=2, ATTR={nested} | + * - ID=3, ATTR={nested} | + * ... --- + */ + @VisibleForTesting + protected static @NonNull Map<String, Integer> parseMulticastGroupsAttribute( + StructNlAttr rootAttribute) { + Map<Short, StructNlAttr> groupAttributes = + GenericNetlinkMsg.getInnerNestedAttributes(rootAttribute); + if (groupAttributes == null) return new HashMap<>(); + + Map<String, Integer> multicastGroups = new HashMap<>(); + for (StructNlAttr groupAttribute : groupAttributes.values()) { + Map<Short, StructNlAttr> groupInnerAttributes = + GenericNetlinkMsg.getInnerNestedAttributes(groupAttribute); + if (groupInnerAttributes == null + || !groupInnerAttributes.containsKey(CTRL_ATTR_MCAST_GRP_NAME) + || !groupInnerAttributes.containsKey(CTRL_ATTR_MCAST_GRP_ID)) { + continue; + } + + String groupName = + groupInnerAttributes.get(CTRL_ATTR_MCAST_GRP_NAME).getValueAsString(); + Integer groupId = groupInnerAttributes.get(CTRL_ATTR_MCAST_GRP_ID).getValueAsInteger(); + if (groupName == null || groupId == null) { + continue; + } + multicastGroups.put(groupName, groupId); + } + return multicastGroups; + } + + /** * Wrapper to construct an Nl80211 request message. * * @param command Command ID for this request. diff --git a/service/tests/wifitests/src/com/android/server/wifi/nl80211/GenericNetlinkMsgTest.java b/service/tests/wifitests/src/com/android/server/wifi/nl80211/GenericNetlinkMsgTest.java index 1d337cb30a..3c3649661a 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/nl80211/GenericNetlinkMsgTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/nl80211/GenericNetlinkMsgTest.java @@ -146,4 +146,21 @@ public class GenericNetlinkMsgTest { assertTrue(invalidSize < buffer.remaining()); assertNull(GenericNetlinkMsg.parseAttributesToMap(buffer, buffer.remaining())); } + + /** + * Test that {@link GenericNetlinkMsg#getInnerNestedAttributes(StructNlAttr)} can parse + * nested attributes. + */ + @Test + public void testGetInnerNestedAttributes() { + // Invalid nested attributes are expected to return null + assertNull(GenericNetlinkMsg.getInnerNestedAttributes(null)); + StructNlAttr intAttribute = new StructNlAttr( + Nl80211TestUtils.TEST_ATTRIBUTE_ID, Nl80211TestUtils.TEST_ATTRIBUTE_VALUE); + assertNull(GenericNetlinkMsg.getInnerNestedAttributes(intAttribute)); + + // The multicast groups attribute is nested and should be parsed correctly + StructNlAttr nestedAttribute = Nl80211TestUtils.createMulticastGroupsAttribute(); + assertNotNull(GenericNetlinkMsg.getInnerNestedAttributes(nestedAttribute)); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211ProxyTest.java b/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211ProxyTest.java index 75de2d6b54..3c1cf17341 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211ProxyTest.java +++ b/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211ProxyTest.java @@ -19,6 +19,9 @@ package com.android.server.wifi.nl80211; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_FAMILY_ID; import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_CMD_NEWFAMILY; import static com.android.server.wifi.nl80211.NetlinkConstants.GENL_ID_CTRL; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_MLME; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_REG; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_SCAN; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -47,6 +50,7 @@ import org.mockito.quality.Strictness; import java.io.FileDescriptor; import java.nio.ByteBuffer; +import java.util.Map; /** * Unit tests for {@link Nl80211Proxy}. @@ -86,6 +90,7 @@ public class Nl80211ProxyTest { CTRL_CMD_NEWFAMILY, GENL_ID_CTRL, (short) 0, 0); familyResponse.addAttribute( new StructNlAttr(CTRL_ATTR_FAMILY_ID, TEST_FAMILY_ID)); + familyResponse.addAttribute(Nl80211TestUtils.createMulticastGroupsAttribute()); setResponseMessage(familyResponse); assertTrue(mDut.initialize()); } @@ -133,4 +138,19 @@ public class Nl80211ProxyTest { GenericNetlinkMsg message = mDut.createNl80211Request(Nl80211TestUtils.TEST_COMMAND); assertEquals(TEST_FAMILY_ID, message.nlHeader.nlmsg_type); } + + /** + * Test that {@link Nl80211Proxy#parseMulticastGroupsAttribute(StructNlAttr)} can parse + * a valid multicast groups attribute. + */ + @Test + public void testParseMulticastGroupsAttribute() { + StructNlAttr multicastGroupsAttribute = Nl80211TestUtils.createMulticastGroupsAttribute(); + Map<String, Integer> parsedMulticastGroups = + Nl80211Proxy.parseMulticastGroupsAttribute(multicastGroupsAttribute); + // Result is expected to contain all the required groups + assertTrue(parsedMulticastGroups.containsKey(NL80211_MULTICAST_GROUP_SCAN)); + assertTrue(parsedMulticastGroups.containsKey(NL80211_MULTICAST_GROUP_REG)); + assertTrue(parsedMulticastGroups.containsKey(NL80211_MULTICAST_GROUP_MLME)); + } } diff --git a/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211TestUtils.java b/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211TestUtils.java index 09f9bd9c18..b9c1d5011b 100644 --- a/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211TestUtils.java +++ b/service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211TestUtils.java @@ -16,6 +16,13 @@ package com.android.server.wifi.nl80211; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GROUPS; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GRP_ID; +import static com.android.server.wifi.nl80211.NetlinkConstants.CTRL_ATTR_MCAST_GRP_NAME; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_MLME; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_REG; +import static com.android.server.wifi.nl80211.NetlinkConstants.NL80211_MULTICAST_GROUP_SCAN; + import com.android.net.module.util.netlink.StructNlAttr; import com.android.net.module.util.netlink.StructNlMsgHdr; @@ -62,4 +69,33 @@ public class Nl80211TestUtils { } return msg; } + + private static void removeNestedAttributeFlag(StructNlAttr attribute) { + // Flag is set by default by the StructNlAttr nested attribute constructor, + // but is not set in nested attributes received from Nl80211 + attribute.nla_type ^= StructNlAttr.NLA_F_NESTED; + } + + private static StructNlAttr createMulticastGroupAttribute( + int index, String groupName, int groupId) { + StructNlAttr nameAttr = new StructNlAttr(CTRL_ATTR_MCAST_GRP_NAME, groupName); + StructNlAttr idAttr = new StructNlAttr(CTRL_ATTR_MCAST_GRP_ID, groupId); + StructNlAttr multicastGroupAttr = new StructNlAttr((short) index, nameAttr, idAttr); + removeNestedAttributeFlag(multicastGroupAttr); + return multicastGroupAttr; + } + + /** + * Create a valid multicast groups attribute. Contains a nested inner attribute for each of + * the required multicast groups. + */ + public static StructNlAttr createMulticastGroupsAttribute() { + StructNlAttr scanAttr = createMulticastGroupAttribute(1, NL80211_MULTICAST_GROUP_SCAN, 10); + StructNlAttr regAttr = createMulticastGroupAttribute(2, NL80211_MULTICAST_GROUP_REG, 11); + StructNlAttr mlmeAttr = createMulticastGroupAttribute(3, NL80211_MULTICAST_GROUP_MLME, 12); + StructNlAttr multicastGroupsAttr = + new StructNlAttr(CTRL_ATTR_MCAST_GROUPS, scanAttr, regAttr, mlmeAttr); + removeNestedAttributeFlag(multicastGroupsAttr); + return multicastGroupsAttr; + } } |