diff mbox series

[v1,2/3] client: add service-allowlist command

Message ID 20210806173706.v1.2.I1d1cf4fbc02b11d62f186f0db23c2c537e296a64@changeid (mailing list archive)
State Superseded
Headers show
Series [v1,1/3] shared/shell: fix missing stdbool in shell.h | expand

Commit Message

Howard Chung Aug. 6, 2021, 9:38 a.m. UTC
From: Yun-Hao Chung <howardchung@chromium.org>

This creates a menu - admin and adds two commands to bluetoothctl
- set-service-allowlist [uuid1 uuid2 ...]
- get-service-allowlist

Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
---
The following test steps were performed:
1. [bluetooth]# - menu admin
2. [bluetooth]# set-service-allowlist 1124 180A 180F 1812 1801
3. [bluetooth]# get-service-allowlist
4. Verify the printed UUIDs are the same as what we set.

 Makefile.tools        |   4 +-
 client/admin_policy.c | 133 ++++++++++++++++++++++++++++++++++++++++++
 client/admin_policy.h |  25 ++++++++
 client/main.c         |  72 +++++++++++++++++++++++
 4 files changed, 233 insertions(+), 1 deletion(-)
 create mode 100644 client/admin_policy.c
 create mode 100644 client/admin_policy.h

Comments

Luiz Augusto von Dentz Aug. 6, 2021, 9:41 p.m. UTC | #1
Hi Howard,

On Fri, Aug 6, 2021 at 2:38 AM Howard Chung <howardchung@google.com> wrote:
>
> From: Yun-Hao Chung <howardchung@chromium.org>
>
> This creates a menu - admin and adds two commands to bluetoothctl
> - set-service-allowlist [uuid1 uuid2 ...]
> - get-service-allowlist

How about we just do:

> allow [clear/uuid1 uuid2 ...]

So when no command is set it just prints the current list and in case
you want to clear it just enter allow clear.

> Reviewed-by: Miao-chen Chou <mcchou@chromium.org>
> ---
> The following test steps were performed:
> 1. [bluetooth]# - menu admin
> 2. [bluetooth]# set-service-allowlist 1124 180A 180F 1812 1801
> 3. [bluetooth]# get-service-allowlist
> 4. Verify the printed UUIDs are the same as what we set.
>
>  Makefile.tools        |   4 +-
>  client/admin_policy.c | 133 ++++++++++++++++++++++++++++++++++++++++++
>  client/admin_policy.h |  25 ++++++++
>  client/main.c         |  72 +++++++++++++++++++++++
>  4 files changed, 233 insertions(+), 1 deletion(-)
>  create mode 100644 client/admin_policy.c
>  create mode 100644 client/admin_policy.h
>
> diff --git a/Makefile.tools b/Makefile.tools
> index c836b5984934..1b493d4d0ed6 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -9,7 +9,9 @@ client_bluetoothctl_SOURCES = client/main.c \
>                                         client/advertising.c \
>                                         client/adv_monitor.h \
>                                         client/adv_monitor.c \
> -                                       client/gatt.h client/gatt.c
> +                                       client/gatt.h client/gatt.c \
> +                                       client/admin_policy.h \
> +                                       client/admin_policy.c
>  client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
>                                 $(GLIB_LIBS) $(DBUS_LIBS) -lreadline
>  endif
> diff --git a/client/admin_policy.c b/client/admin_policy.c
> new file mode 100644
> index 000000000000..21062c4f6185
> --- /dev/null
> +++ b/client/admin_policy.c
> @@ -0,0 +1,133 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2021 Google LLC
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +
> +#include "gdbus/gdbus.h"
> +#include "src/shared/shell.h"
> +
> +#include "admin_policy.h"
> +#define _GNU_SOURCE
> +
> +static GDBusProxy *set_proxy;
> +static GDBusProxy *status_proxy;
> +
> +void admin_policy_set_set_proxy(GDBusProxy *proxy)
> +{
> +       set_proxy = proxy;
> +}
> +
> +void admin_policy_set_status_proxy(GDBusProxy *proxy)
> +{
> +       status_proxy = proxy;
> +}
> +
> +void admin_policy_read_service_allowlist(DBusConnection *dbus_conn)
> +{
> +       DBusMessageIter iter, subiter;
> +       char *uuid = NULL;
> +
> +       if (!status_proxy || !g_dbus_proxy_get_property(status_proxy,
> +                                               "ServiceAllowList", &iter)) {
> +               bt_shell_printf("Failed to get property\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
> +               bt_shell_printf("Unexpected return type\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       bt_shell_printf("Service AllowedList:\n");
> +       dbus_message_iter_recurse(&iter, &subiter);
> +       while (dbus_message_iter_get_arg_type(&subiter) ==
> +                                               DBUS_TYPE_STRING) {
> +               dbus_message_iter_get_basic(&subiter, &uuid);
> +               bt_shell_printf("\t%s\n", uuid);
> +               dbus_message_iter_next(&subiter);
> +       }
> +
> +       return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +}
> +
> +struct uuid_list_data {
> +       char **uuid_list;
> +       size_t num;
> +};
> +
> +static void set_service_setup(DBusMessageIter *iter, void *user_data)
> +{
> +       struct uuid_list_data *data = user_data;
> +       DBusMessageIter arr_iter;
> +       size_t i;
> +
> +       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
> +                                               DBUS_TYPE_STRING_AS_STRING,
> +                                               &arr_iter);
> +
> +       for (i = 0; i < data->num; i++) {
> +               dbus_message_iter_append_basic(&arr_iter, DBUS_TYPE_STRING,
> +                                                       &data->uuid_list[i]);
> +       }
> +
> +       dbus_message_iter_close_container(iter, &arr_iter);
> +}
> +
> +static void set_service_reply(DBusMessage *message, void *user_data)
> +{
> +       DBusError error;
> +
> +       dbus_error_init(&error);
> +
> +       if (!dbus_set_error_from_message(&error, message)) {
> +               bt_shell_printf("Set allowed service successfully\n");
> +               return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +       }
> +
> +       bt_shell_printf("Failed to set service allowed list: %s\n", error.name);
> +       dbus_error_free(&error);
> +       return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +}
> +
> +void admin_policy_set_service_allowlist(DBusConnection *dbus_connd,
> +                                                       int argc, char *argv[])
> +{
> +       struct uuid_list_data data;
> +
> +       if (!set_proxy) {
> +               bt_shell_printf("Set proxy not ready\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +
> +       data.uuid_list = argv;
> +       data.num = argc;
> +
> +       if (!g_dbus_proxy_method_call(set_proxy, "SetServiceAllowList",
> +                                       set_service_setup, set_service_reply,
> +                                       &data, NULL)) {
> +               bt_shell_printf("Failed to call method\n");
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +       }
> +}
> diff --git a/client/admin_policy.h b/client/admin_policy.h
> new file mode 100644
> index 000000000000..1c8c2152d59d
> --- /dev/null
> +++ b/client/admin_policy.h
> @@ -0,0 +1,25 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2021 Google LLC
> + *
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + */
> +
> +void admin_policy_set_set_proxy(GDBusProxy *proxy);
> +void admin_policy_set_status_proxy(GDBusProxy *proxy);
> +
> +void admin_policy_read_service_allowlist(DBusConnection *dbus_conn);
> +void admin_policy_set_service_allowlist(DBusConnection *dbus_conn,
> +                                                       int argc, char *argv[]);
> diff --git a/client/main.c b/client/main.c
> index c1a62edb7f99..5297760c8cec 100644
> --- a/client/main.c
> +++ b/client/main.c
> @@ -29,6 +29,7 @@
>  #include "gatt.h"
>  #include "advertising.h"
>  #include "adv_monitor.h"
> +#include "admin_policy.h"
>
>  /* String display constants */
>  #define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
> @@ -530,6 +531,23 @@ static void admon_manager_added(GDBusProxy *proxy)
>         adv_monitor_register_app(dbus_conn);
>  }
>
> +static void admin_policy_set_added(GDBusProxy *proxy)
> +{
> +       admin_policy_set_set_proxy(proxy);
> +}
> +
> +static void admin_policy_status_added(GDBusProxy *proxy)
> +{
> +       struct adapter *adapter;
> +
> +       adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
> +
> +       if (!adapter)
> +               return;
> +
> +       admin_policy_set_status_proxy(proxy);
> +}
> +
>  static void proxy_added(GDBusProxy *proxy, void *user_data)
>  {
>         const char *interface;
> @@ -565,6 +583,10 @@ static void proxy_added(GDBusProxy *proxy, void *user_data)
>         } else if (!strcmp(interface,
>                                 "org.bluez.AdvertisementMonitorManager1")) {
>                 admon_manager_added(proxy);
> +       } else if (!strcmp(interface, "org.bluez.AdminPolicySet1")) {
> +               admin_policy_set_added(proxy);
> +       } else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1")) {
> +               admin_policy_status_added(proxy);
>         }
>  }
>
> @@ -621,6 +643,23 @@ static void adapter_removed(GDBusProxy *proxy)
>         }
>  }
>
> +static void admin_policy_set_removed(GDBusProxy *proxy)
> +{
> +       admin_policy_set_set_proxy(NULL);
> +}
> +
> +static void admin_policy_status_removed(GDBusProxy *proxy)
> +{
> +       struct adapter *adapter;
> +
> +       adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
> +
> +       if (!adapter)
> +               return;
> +
> +       admin_policy_set_status_proxy(NULL);
> +}
> +
>  static void proxy_removed(GDBusProxy *proxy, void *user_data)
>  {
>         const char *interface;
> @@ -661,6 +700,10 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
>         } else if (!strcmp(interface,
>                         "org.bluez.AdvertisementMonitorManager1")) {
>                 adv_monitor_remove_manager(dbus_conn);
> +       } else if (!strcmp(interface, "org.bluez.AdminPolicySet1")) {
> +               admin_policy_set_removed(proxy);
> +       } else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1")) {
> +               admin_policy_status_removed(proxy);
>         }
>  }
>
> @@ -2824,6 +2867,22 @@ static void cmd_adv_monitor_get_supported_info(int argc, char *argv[])
>         adv_monitor_get_supported_info();
>  }
>
> +static void cmd_set_service_allowlist(int argc, char *argv[])
> +{
> +       if (check_default_ctrl() == FALSE)
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +
> +       admin_policy_set_service_allowlist(dbus_conn, argc - 1, argv + 1);
> +}
> +
> +static void cmd_get_service_allowlist(int argc, char *argv[])
> +{
> +       if (check_default_ctrl() == FALSE)
> +               return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +
> +       admin_policy_read_service_allowlist(dbus_conn);
> +}
> +
>  static const struct bt_shell_menu advertise_menu = {
>         .name = "advertise",
>         .desc = "Advertise Options Submenu",
> @@ -2978,6 +3037,18 @@ static const struct bt_shell_menu gatt_menu = {
>         { } },
>  };
>
> +static const struct bt_shell_menu admin_menu = {
> +       .name = "admin",
> +       .desc = "Admin Policy Submenu",
> +       .entries = {
> +       { "set-service-allowlist", "[uuid1 uuid2 ...]",
> +                                               cmd_set_service_allowlist,
> +                                               "Set service allowlist"},
> +       { "get-service-allowlist", NULL, cmd_get_service_allowlist,
> +                                               "Get service allowlist"},
> +       {} },
> +};
> +
>  static const struct bt_shell_menu main_menu = {
>         .name = "main",
>         .entries = {
> @@ -3075,6 +3146,7 @@ int main(int argc, char *argv[])
>         bt_shell_add_submenu(&advertise_monitor_menu);
>         bt_shell_add_submenu(&scan_menu);
>         bt_shell_add_submenu(&gatt_menu);
> +       bt_shell_add_submenu(&admin_menu);
>         bt_shell_set_prompt(PROMPT_OFF);
>
>         if (agent_option)
> --
> 2.32.0.605.g8dce9f2422-goog
>
diff mbox series

Patch

diff --git a/Makefile.tools b/Makefile.tools
index c836b5984934..1b493d4d0ed6 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -9,7 +9,9 @@  client_bluetoothctl_SOURCES = client/main.c \
 					client/advertising.c \
 					client/adv_monitor.h \
 					client/adv_monitor.c \
-					client/gatt.h client/gatt.c
+					client/gatt.h client/gatt.c \
+					client/admin_policy.h \
+					client/admin_policy.c
 client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
 				$(GLIB_LIBS) $(DBUS_LIBS) -lreadline
 endif
diff --git a/client/admin_policy.c b/client/admin_policy.c
new file mode 100644
index 000000000000..21062c4f6185
--- /dev/null
+++ b/client/admin_policy.c
@@ -0,0 +1,133 @@ 
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2021 Google LLC
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "gdbus/gdbus.h"
+#include "src/shared/shell.h"
+
+#include "admin_policy.h"
+#define _GNU_SOURCE
+
+static GDBusProxy *set_proxy;
+static GDBusProxy *status_proxy;
+
+void admin_policy_set_set_proxy(GDBusProxy *proxy)
+{
+	set_proxy = proxy;
+}
+
+void admin_policy_set_status_proxy(GDBusProxy *proxy)
+{
+	status_proxy = proxy;
+}
+
+void admin_policy_read_service_allowlist(DBusConnection *dbus_conn)
+{
+	DBusMessageIter iter, subiter;
+	char *uuid = NULL;
+
+	if (!status_proxy || !g_dbus_proxy_get_property(status_proxy,
+						"ServiceAllowList", &iter)) {
+		bt_shell_printf("Failed to get property\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+		bt_shell_printf("Unexpected return type\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	bt_shell_printf("Service AllowedList:\n");
+	dbus_message_iter_recurse(&iter, &subiter);
+	while (dbus_message_iter_get_arg_type(&subiter) ==
+						DBUS_TYPE_STRING) {
+		dbus_message_iter_get_basic(&subiter, &uuid);
+		bt_shell_printf("\t%s\n", uuid);
+		dbus_message_iter_next(&subiter);
+	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+
+struct uuid_list_data {
+	char **uuid_list;
+	size_t num;
+};
+
+static void set_service_setup(DBusMessageIter *iter, void *user_data)
+{
+	struct uuid_list_data *data = user_data;
+	DBusMessageIter arr_iter;
+	size_t i;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+						DBUS_TYPE_STRING_AS_STRING,
+						&arr_iter);
+
+	for (i = 0; i < data->num; i++) {
+		dbus_message_iter_append_basic(&arr_iter, DBUS_TYPE_STRING,
+							&data->uuid_list[i]);
+	}
+
+	dbus_message_iter_close_container(iter, &arr_iter);
+}
+
+static void set_service_reply(DBusMessage *message, void *user_data)
+{
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	if (!dbus_set_error_from_message(&error, message)) {
+		bt_shell_printf("Set allowed service successfully\n");
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+	}
+
+	bt_shell_printf("Failed to set service allowed list: %s\n", error.name);
+	dbus_error_free(&error);
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
+}
+
+void admin_policy_set_service_allowlist(DBusConnection *dbus_connd,
+							int argc, char *argv[])
+{
+	struct uuid_list_data data;
+
+	if (!set_proxy) {
+		bt_shell_printf("Set proxy not ready\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+
+	data.uuid_list = argv;
+	data.num = argc;
+
+	if (!g_dbus_proxy_method_call(set_proxy, "SetServiceAllowList",
+					set_service_setup, set_service_reply,
+					&data, NULL)) {
+		bt_shell_printf("Failed to call method\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	}
+}
diff --git a/client/admin_policy.h b/client/admin_policy.h
new file mode 100644
index 000000000000..1c8c2152d59d
--- /dev/null
+++ b/client/admin_policy.h
@@ -0,0 +1,25 @@ 
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2021 Google LLC
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ */
+
+void admin_policy_set_set_proxy(GDBusProxy *proxy);
+void admin_policy_set_status_proxy(GDBusProxy *proxy);
+
+void admin_policy_read_service_allowlist(DBusConnection *dbus_conn);
+void admin_policy_set_service_allowlist(DBusConnection *dbus_conn,
+							int argc, char *argv[]);
diff --git a/client/main.c b/client/main.c
index c1a62edb7f99..5297760c8cec 100644
--- a/client/main.c
+++ b/client/main.c
@@ -29,6 +29,7 @@ 
 #include "gatt.h"
 #include "advertising.h"
 #include "adv_monitor.h"
+#include "admin_policy.h"
 
 /* String display constants */
 #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
@@ -530,6 +531,23 @@  static void admon_manager_added(GDBusProxy *proxy)
 	adv_monitor_register_app(dbus_conn);
 }
 
+static void admin_policy_set_added(GDBusProxy *proxy)
+{
+	admin_policy_set_set_proxy(proxy);
+}
+
+static void admin_policy_status_added(GDBusProxy *proxy)
+{
+	struct adapter *adapter;
+
+	adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
+
+	if (!adapter)
+		return;
+
+	admin_policy_set_status_proxy(proxy);
+}
+
 static void proxy_added(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -565,6 +583,10 @@  static void proxy_added(GDBusProxy *proxy, void *user_data)
 	} else if (!strcmp(interface,
 				"org.bluez.AdvertisementMonitorManager1")) {
 		admon_manager_added(proxy);
+	} else if (!strcmp(interface, "org.bluez.AdminPolicySet1")) {
+		admin_policy_set_added(proxy);
+	} else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1")) {
+		admin_policy_status_added(proxy);
 	}
 }
 
@@ -621,6 +643,23 @@  static void adapter_removed(GDBusProxy *proxy)
 	}
 }
 
+static void admin_policy_set_removed(GDBusProxy *proxy)
+{
+	admin_policy_set_set_proxy(NULL);
+}
+
+static void admin_policy_status_removed(GDBusProxy *proxy)
+{
+	struct adapter *adapter;
+
+	adapter = find_ctrl(ctrl_list, g_dbus_proxy_get_path(proxy));
+
+	if (!adapter)
+		return;
+
+	admin_policy_set_status_proxy(NULL);
+}
+
 static void proxy_removed(GDBusProxy *proxy, void *user_data)
 {
 	const char *interface;
@@ -661,6 +700,10 @@  static void proxy_removed(GDBusProxy *proxy, void *user_data)
 	} else if (!strcmp(interface,
 			"org.bluez.AdvertisementMonitorManager1")) {
 		adv_monitor_remove_manager(dbus_conn);
+	} else if (!strcmp(interface, "org.bluez.AdminPolicySet1")) {
+		admin_policy_set_removed(proxy);
+	} else if (!strcmp(interface, "org.bluez.AdminPolicyStatus1")) {
+		admin_policy_status_removed(proxy);
 	}
 }
 
@@ -2824,6 +2867,22 @@  static void cmd_adv_monitor_get_supported_info(int argc, char *argv[])
 	adv_monitor_get_supported_info();
 }
 
+static void cmd_set_service_allowlist(int argc, char *argv[])
+{
+	if (check_default_ctrl() == FALSE)
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+
+	admin_policy_set_service_allowlist(dbus_conn, argc - 1, argv + 1);
+}
+
+static void cmd_get_service_allowlist(int argc, char *argv[])
+{
+	if (check_default_ctrl() == FALSE)
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+
+	admin_policy_read_service_allowlist(dbus_conn);
+}
+
 static const struct bt_shell_menu advertise_menu = {
 	.name = "advertise",
 	.desc = "Advertise Options Submenu",
@@ -2978,6 +3037,18 @@  static const struct bt_shell_menu gatt_menu = {
 	{ } },
 };
 
+static const struct bt_shell_menu admin_menu = {
+	.name = "admin",
+	.desc = "Admin Policy Submenu",
+	.entries = {
+	{ "set-service-allowlist", "[uuid1 uuid2 ...]",
+						cmd_set_service_allowlist,
+						"Set service allowlist"},
+	{ "get-service-allowlist", NULL, cmd_get_service_allowlist,
+						"Get service allowlist"},
+	{} },
+};
+
 static const struct bt_shell_menu main_menu = {
 	.name = "main",
 	.entries = {
@@ -3075,6 +3146,7 @@  int main(int argc, char *argv[])
 	bt_shell_add_submenu(&advertise_monitor_menu);
 	bt_shell_add_submenu(&scan_menu);
 	bt_shell_add_submenu(&gatt_menu);
+	bt_shell_add_submenu(&admin_menu);
 	bt_shell_set_prompt(PROMPT_OFF);
 
 	if (agent_option)