summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
author Gabriel Biren <gbiren@google.com> 2024-08-03 19:57:58 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2024-08-03 19:57:58 +0000
commite4a5d144d16eca6501ba948b2371fec32a3f5db0 (patch)
treed645cdb555b6f72f6d25564c1ad266fa872a4816 /service
parenta776d6fe1b8e6f45c7dfc6c52c963e8e13ff2aec (diff)
parent41540041f1b96b0edda9c462c746bf7e64414c31 (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')
-rw-r--r--service/java/com/android/server/wifi/nl80211/GenericNetlinkMsg.java16
-rw-r--r--service/java/com/android/server/wifi/nl80211/NetlinkConstants.java8
-rw-r--r--service/java/com/android/server/wifi/nl80211/Nl80211Proxy.java71
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/nl80211/GenericNetlinkMsgTest.java17
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211ProxyTest.java20
-rw-r--r--service/tests/wifitests/src/com/android/server/wifi/nl80211/Nl80211TestUtils.java36
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;
+ }
}