git: ad91d47db306 - main - bluetooth: signal devd on netgraph device events

From: Adrian Chadd <adrian_at_FreeBSD.org>
Date: Sun, 12 Jul 2026 18:47:30 UTC
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=ad91d47db306738cc29f30c4d506509a3f5eeb8c

commit ad91d47db306738cc29f30c4d506509a3f5eeb8c
Author:     -k <slowdive@me.com>
AuthorDate: 2026-07-12 18:16:09 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-07-12 18:28:15 +0000

    bluetooth: signal devd on netgraph device events
    
    Currently, devd emits events for external adapters only.
    
    Send Netgraph init/disconnect events to devd so the internal adapter's
    state could be asserted from userland.
    
    (adrian - indentation changes.)
    
    Signed-off-by: Kirill Orlov (-k) <slowdive@me.com>
    Reviewed-by: adrian, imp
    Pull-Request: https://github.com/freebsd/freebsd-src/pull/2196
---
 sbin/devd/devd.conf                      | 15 +++++++
 sys/netgraph/bluetooth/hci/ng_hci_main.c | 71 ++++++++++++++++++++++++++++++++
 2 files changed, 86 insertions(+)

diff --git a/sbin/devd/devd.conf b/sbin/devd/devd.conf
index 86faf2f30722..9fa11463cd42 100644
--- a/sbin/devd/devd.conf
+++ b/sbin/devd/devd.conf
@@ -159,4 +159,19 @@ notify 100 {
 	action "/sbin/init q";
 };
 
+# Track the bluetooth adapter's arrival/departure. This is useful
+# for internal adapters that do not emit regular device events.
+notify 100 {
+	match "system"		"BLUETOOTH";
+	match "subsystem"	"HCI";
+	match "type"		"INITIALIZED";
+	action "logger 'Bluetooth adapter initialized: $*'";
+};
+notify 100 {
+	match "system"		"BLUETOOTH";
+	match "subsystem"	"HCI";
+	match "type"		"POWERED_OFF";
+	action "logger 'Bluetooth adapter powered off: $*'";
+};
+
 */
diff --git a/sys/netgraph/bluetooth/hci/ng_hci_main.c b/sys/netgraph/bluetooth/hci/ng_hci_main.c
index 13bf970f0135..190cb80a1c4c 100644
--- a/sys/netgraph/bluetooth/hci/ng_hci_main.c
+++ b/sys/netgraph/bluetooth/hci/ng_hci_main.c
@@ -33,7 +33,10 @@
  */
 
 #include <sys/param.h>
+#include <sys/devctl.h>
+#include <sys/sbuf.h>
 #include <sys/systm.h>
+#include <sys/syslog.h>
 #include <sys/kernel.h>
 #include <sys/endian.h>
 #include <sys/malloc.h>
@@ -110,6 +113,19 @@ static int ng_hci_linktype_to_addrtype(int linktype)
 	}
 	return BDADDR_BREDR;
 }
+
+/*
+ * Append bdaddr_t as "xx:xx:xx:xx:xx:xx" to sbuf.
+ */
+
+static void
+ng_hci_append_bdaddr_to_sbuf(struct sbuf *sb, const bdaddr_t *ba)
+{
+	sbuf_printf(sb, "%02x:%02x:%02x:%02x:%02x:%02x",
+		ba->b[5], ba->b[4], ba->b[3],
+		ba->b[2], ba->b[1], ba->b[0]);
+} /* ng_hci_append_bdaddr_to_sbuf */
+
 /*****************************************************************************
  *****************************************************************************
  **                   Netgraph methods implementation
@@ -268,6 +284,31 @@ ng_hci_disconnect(hook_p hook)
 		/* Connection terminated by local host */
 		ng_hci_unit_clean(unit, 0x16);
 		unit->state &= ~(NG_HCI_UNIT_CONNECTED|NG_HCI_UNIT_INITED);
+
+		/* Signal power off to devd */
+		{
+			struct sbuf *sb;
+			sb = sbuf_new_auto();
+			sbuf_printf(sb, "node=%s bdaddr=",
+			    NG_NODE_NAME(NG_HOOK_NODE(hook)));
+			ng_hci_append_bdaddr_to_sbuf(sb, &unit->bdaddr);
+			sbuf_printf(sb, "\n");
+
+			if (sbuf_finish(sb) > 0) {
+				log(LOG_WARNING,
+					"hci: failed to signal bt device " \
+					"power off to devd: " \
+					"%02x:%02x:%02x:%02x:%02x:%02x\n",
+					unit->bdaddr.b[5], unit->bdaddr.b[4],
+					unit->bdaddr.b[3], unit->bdaddr.b[2],
+					unit->bdaddr.b[1], unit->bdaddr.b[0]);
+			} else {
+				devctl_notify("BLUETOOTH", "HCI",
+				    "POWERED_OFF", sbuf_data(sb));
+			}
+
+			sbuf_delete(sb);
+		}
 	} else
 		return (EINVAL);
 
@@ -371,6 +412,36 @@ ng_hci_default_rcvmsg(node_p node, item_p item, hook_p lasthook)
 
 			ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);
 			ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);
+
+			 /* Signal init to devd */
+			{
+				struct sbuf *sb;
+				sb = sbuf_new_auto();
+				sbuf_printf(sb, "node=%s bdaddr=",
+				    NG_NODE_NAME(node));
+				ng_hci_append_bdaddr_to_sbuf(sb,
+				    &unit->bdaddr);
+				sbuf_printf(sb, "\n");
+
+				if (sbuf_finish(sb) > 0) {
+					log(LOG_WARNING,
+						"hci: failed to signal bt " \
+						"device init to devd: "
+						"%02x:%02x:%02x:%02x:%02x:%02x\n",
+						unit->bdaddr.b[5],
+						unit->bdaddr.b[4],
+						unit->bdaddr.b[3],
+						unit->bdaddr.b[2],
+						unit->bdaddr.b[1],
+						unit->bdaddr.b[0]);
+				} else {
+					devctl_notify("BLUETOOTH", "HCI",
+					    "INITIALIZED", sbuf_data(sb));
+				}
+
+				sbuf_delete(sb);
+			}
+
 			break;
 
 		/* Get node debug level */