[RFC PATCH BlueZ v2 4/7] mesh: gatt-proxy: support for proxy configuration messages and filtering

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Implement reception / responses for Proxy Configuration Messages
(MshPRT_v1.1, section 6.6) and proxy filtering (sections 6.4 and 6.7).
---
 Makefile.mesh         |   3 +-
 mesh/crypto.c         |   6 +-
 mesh/crypto.h         |   3 +
 mesh/gatt-proxy-svc.c | 182 +++++++++++++++++++++++++++++++++++++++++-
 mesh/gatt-proxy-svc.h |  16 +++-
 mesh/net-keys.c       |  56 +++++++++++++
 mesh/net-keys.h       |   3 +
 mesh/net.c            | 104 +++++++++++++++++++++---
 mesh/proxy-cfg.c      | 168 ++++++++++++++++++++++++++++++++++++++
 mesh/proxy-cfg.h      |  19 +++++
 10 files changed, 541 insertions(+), 19 deletions(-)
 create mode 100644 mesh/proxy-cfg.c
 create mode 100644 mesh/proxy-cfg.h

diff --git a/Makefile.mesh b/Makefile.mesh
index 8a190f75de9d..d39bb17eca70 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -41,7 +41,8 @@ mesh_sources = mesh/mesh.h mesh/mesh.c \
 				mesh/prv-beacon.h mesh/prvbeac-server.c \
 				mesh/mesh-defs.h \
 				mesh/gatt-service.h mesh/gatt-service.c \
-				mesh/gatt-proxy-svc.h mesh/gatt-proxy-svc.c
+				mesh/gatt-proxy-svc.h mesh/gatt-proxy-svc.c \
+				mesh/proxy-cfg.h mesh/proxy-cfg.c
 pkglibexec_PROGRAMS += mesh/bluetooth-meshd
 
 mesh/mesh.$(OBJEXT): ell/internal
diff --git a/mesh/crypto.c b/mesh/crypto.c
index 451be81d2fb3..a98836349517 100644
--- a/mesh/crypto.c
+++ b/mesh/crypto.c
@@ -590,7 +590,7 @@ bool mesh_crypto_packet_build(bool ctl, uint8_t ttl,
 	return true;
 }
 
-static bool network_header_parse(const uint8_t *packet, uint8_t packet_len,
+bool mesh_crypto_network_header_parse(const uint8_t *packet, uint8_t packet_len,
 				bool *ctl, uint8_t *ttl, uint32_t *seq,
 				uint16_t *src, uint16_t *dst)
 {
@@ -630,7 +630,7 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 	uint16_t this_dst;
 	bool is_segmented;
 
-	if (!network_header_parse(packet, packet_len,
+	if (!mesh_crypto_network_header_parse(packet, packet_len,
 					ctl, ttl, seq, src, &this_dst))
 		return false;
 
@@ -843,7 +843,7 @@ bool mesh_crypto_packet_encode(uint8_t *packet, uint8_t packet_len,
 	uint16_t src;
 	uint16_t dst;
 
-	if (!network_header_parse(packet, packet_len,
+	if (!mesh_crypto_network_header_parse(packet, packet_len,
 						&ctl, &ttl, &seq, &src, &dst))
 		return false;
 
diff --git a/mesh/crypto.h b/mesh/crypto.h
index e4bbe4343223..43d4ffaa5023 100644
--- a/mesh/crypto.h
+++ b/mesh/crypto.h
@@ -74,6 +74,9 @@ bool mesh_crypto_packet_parse(const uint8_t *packet, uint8_t packet_len,
 				bool *szmic, bool *relay, uint16_t *seqZero,
 				uint8_t *segO, uint8_t *segN,
 				const uint8_t **payload, uint8_t *payload_len);
+bool mesh_crypto_network_header_parse(const uint8_t *packet, uint8_t packet_len,
+				bool *ctl, uint8_t *ttl, uint32_t *seq,
+				uint16_t *src, uint16_t *dst);
 bool mesh_crypto_payload_encrypt(uint8_t *aad, const uint8_t *payload,
 				uint8_t *out, uint16_t payload_len,
 				uint16_t src, uint16_t dst, uint8_t key_aid,
diff --git a/mesh/gatt-proxy-svc.c b/mesh/gatt-proxy-svc.c
index 27cc22c0572a..4100578a9f0a 100644
--- a/mesh/gatt-proxy-svc.c
+++ b/mesh/gatt-proxy-svc.c
@@ -10,17 +10,21 @@
 
 #include <stdbool.h>
 #include <stdlib.h>
-#include <string.h>			// memcpy()
+#include <string.h>			// memcpy(), memmove()
 
 #include <ell/dbus.h>
 #include <ell/log.h>			// l_warn()
 #include <ell/queue.h>
 #include <ell/timeout.h>
-#include <ell/util.h>			// ell_new(), l_free(), l_malloc()
+#include <ell/util.h>			// ell_new(), l_free(), l_malloc(),
+					// L_ARRAY_SIZE
 
+#include "mesh/mesh-defs.h"		// UNASSIGNED_ADDRESS
 #include "mesh/gatt-service.h"
 #include "mesh/mesh-io.h"		// mesh_io_recv_func_t
-#include "mesh/net.h"			// mesh_net_attach_gatt(),
+#include "mesh/net.h"			// PROXY_FILTER_ACCEPT_LIST,
+					// PROXY_FILTER_REJECT_LIST
+					// mesh_net_attach_gatt(),
 					// mesh_net_detach_gatt()
 #include "mesh/net-keys.h"		// net_key_fill_adv_service_data(),
 					// net_key_get_next_id()
@@ -47,6 +51,9 @@ struct gatt_proxy_svc {
 	bool txing;
 	struct l_queue *tx_deferred;
 	struct l_queue *rx_regs;
+	uint8_t filter_type;
+	uint16_t filter_addrs[32];
+	unsigned filter_count;
 };
 
 struct process_data {
@@ -117,6 +124,136 @@ void gatt_proxy_svc_deregister_recv_cb(struct gatt_proxy_svc *gatt_proxy,
 	l_free(rx_reg);
 }
 
+void gatt_proxy_svc_filter_set_type(struct gatt_proxy_svc *gatt_proxy,
+							uint8_t filter_type)
+{
+	if (!gatt_proxy || gatt_proxy != gatt_proxy_svc)
+		return;
+
+	/* Behavior not specified in MshPRT, section 6.7 */
+	if (filter_type != PROXY_FILTER_ACCEPT_LIST &&
+					filter_type != PROXY_FILTER_REJECT_LIST)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If a Proxy Server receives a Set Filter Type message, it shall set
+	 * the proxy filter type as requested in the message parameter, and it
+	 * shall clear the proxy filter list.
+	 */
+	gatt_proxy->filter_type = filter_type;
+	gatt_proxy->filter_count = 0;
+}
+
+void gatt_proxy_svc_filter_add(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t addr)
+{
+	int i;
+
+	if (!gatt_proxy || gatt_proxy != gatt_proxy_svc)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If the AddressArray field contains the unassigned address, the Proxy
+	 * Server shall ignore that address.
+	 */
+	if (addr == UNASSIGNED_ADDRESS)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If the Proxy Server runs out of space in the proxy filter list,
+	 * the Proxy Server shall not add these addresses.
+	 */
+	if (gatt_proxy->filter_count == L_ARRAY_SIZE(gatt_proxy->filter_addrs))
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If one or more addresses contained in the message are already in the
+	 * list, the Proxy Server shall not add these addresses.
+	 */
+	for (i = 0; i < gatt_proxy->filter_count; i++)
+		if (gatt_proxy->filter_addrs[i] == addr)
+			return;
+
+	gatt_proxy->filter_addrs[gatt_proxy->filter_count++] = addr;
+}
+
+void gatt_proxy_svc_filter_remove(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t addr)
+{
+	int i;
+
+	if (!gatt_proxy || gatt_proxy != gatt_proxy_svc)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If the AddressArray field contains the unassigned address, the Proxy
+	 * Server shall ignore that address.
+	 */
+	if (addr == UNASSIGNED_ADDRESS)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * If one or more addresses contained in the message were not in the
+	 * list, the Proxy Server shall ignore these addresses.
+	 */
+	for (i = 0; i < gatt_proxy->filter_count; i++)
+		if (gatt_proxy->filter_addrs[i] == addr)
+			break;
+
+	if (i == gatt_proxy->filter_count)
+		return;
+
+	memmove(gatt_proxy->filter_addrs + i, gatt_proxy->filter_addrs + i + 1,
+			gatt_proxy->filter_count - i - 1);
+	gatt_proxy->filter_count--;
+}
+
+unsigned gatt_proxy_svc_filter_count(struct gatt_proxy_svc *gatt_proxy,
+							uint8_t *filter_type)
+{
+	if (!gatt_proxy || gatt_proxy != gatt_proxy_svc)
+		return 0;
+
+	*filter_type = gatt_proxy->filter_type;
+
+	return gatt_proxy->filter_count;
+}
+
+void gatt_proxy_svc_filter_pdu_rcvd(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t src)
+{
+	if (!gatt_proxy || gatt_proxy != gatt_proxy_svc)
+		return;
+
+	if (gatt_proxy->filter_type == PROXY_FILTER_ACCEPT_LIST) {
+		/*
+		 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+		 * If the proxy filter is an accept list filter, upon receiving
+		 * a Proxy PDU containing a valid Network PDU from the Proxy
+		 * Client, the Proxy Server shall add the unicast address
+		 * contained in the SRC field of the Network PDU to the accept
+		 * list.
+		 */
+		gatt_proxy_svc_filter_add(gatt_proxy, src);
+	} else {
+		/*
+		 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+		 * If the proxy filter is a reject list filter, upon receiving a
+		 * Proxy PDU containing a valid Network PDU from the Proxy
+		 * Client, the Proxy Server shall remove the unicast address
+		 * contained in the SRC field of the Network PDU from the reject
+		 * list.
+		 */
+		gatt_proxy_svc_filter_remove(gatt_proxy, src);
+	}
+}
+
 static void gatt_proxy_svc_send(enum proxy_msg_type msg_type, const void *data,
 								uint8_t len)
 {
@@ -144,11 +281,40 @@ static void gatt_proxy_svc_send(enum proxy_msg_type msg_type, const void *data,
 	}
 }
 
-void gatt_proxy_svc_send_net(const void *data, uint8_t len)
+void gatt_proxy_svc_send_net(uint16_t dst, const void *data, uint8_t len)
 {
+	int i;
+
+	if (!gatt_proxy_svc)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 6.4 - Proxy filtering
+	 * The output filter of the network interface (see Section 3.4.5) [...]
+	 * can be configured by the Proxy Client. This allows the Proxy Client
+	 * to explicitly request to receive only mesh messages with certain
+	 * *destination* addresses.
+	 */
+	for (i = 0; i < gatt_proxy_svc->filter_count; i++)
+		if (gatt_proxy_svc->filter_addrs[i] == dst)
+			break;
+
+	if (gatt_proxy_svc->filter_type == PROXY_FILTER_ACCEPT_LIST) {
+		if (i == gatt_proxy_svc->filter_count)  // not found
+			return;
+	} else {  /* PROXY_FILTER_REJECT_LIST */
+		if (i != gatt_proxy_svc->filter_count)  // found
+			return;
+	}
+
 	gatt_proxy_svc_send(PROXY_MSG_TYPE_NETWORK_PDU, data, len);
 }
 
+void gatt_proxy_svc_send_proxy_cfg(const void *data, uint8_t len)
+{
+	gatt_proxy_svc_send(PROXY_MSG_TYPE_PROXY_CFG, data, len);
+}
+
 static void gatt_service_notify_acquired(void *user_data)
 {
 	struct gatt_proxy_svc *gatt_proxy = user_data;
@@ -157,6 +323,14 @@ static void gatt_service_notify_acquired(void *user_data)
 		return;
 
 	gatt_proxy->connected = true;
+
+	/*
+	 * MshPRT_v1.1, section 6.7 - Proxy Server behavior
+	 * Upon connection, the Proxy Server shall initialize the proxy filter
+	 * as an accept list filter and the accept list shall be empty.
+	 */
+	gatt_proxy->filter_type = PROXY_FILTER_ACCEPT_LIST;
+	gatt_proxy->filter_count = 0;
 }
 
 static void gatt_service_notify_stopped(void *user_data)
diff --git a/mesh/gatt-proxy-svc.h b/mesh/gatt-proxy-svc.h
index 2b0c9d7ec21b..0abb85d7109f 100644
--- a/mesh/gatt-proxy-svc.h
+++ b/mesh/gatt-proxy-svc.h
@@ -24,5 +24,17 @@ void gatt_proxy_svc_register_recv_cb(struct gatt_proxy_svc *gatt_proxy,
 					void *user_data);
 void gatt_proxy_svc_deregister_recv_cb(struct gatt_proxy_svc *gatt_proxy,
 						enum proxy_msg_type msg_type);
-void gatt_proxy_svc_send_net(const void *data, uint8_t len);
-								
+
+void gatt_proxy_svc_filter_set_type(struct gatt_proxy_svc *gatt_proxy,
+							uint8_t filter_type);
+void gatt_proxy_svc_filter_add(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t addr);
+void gatt_proxy_svc_filter_remove(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t addr);
+unsigned gatt_proxy_svc_filter_count(struct gatt_proxy_svc *gatt_proxy,
+							uint8_t *filter_type);
+void gatt_proxy_svc_filter_pdu_rcvd(struct gatt_proxy_svc *gatt_proxy,
+								uint16_t src);
+
+void gatt_proxy_svc_send_net(uint16_t dst, const void *data, uint8_t len);
+void gatt_proxy_svc_send_proxy_cfg(const void *data, uint8_t len);
diff --git a/mesh/net-keys.c b/mesh/net-keys.c
index ab724f9cfa1e..1a2cd39421c1 100644
--- a/mesh/net-keys.c
+++ b/mesh/net-keys.c
@@ -78,6 +78,15 @@ struct net_key {
 	bool ivu;
 };
 
+struct proxy_cfg_msg {
+	const uint8_t *data;
+	uint8_t len;
+	uint8_t *plain;
+	uint8_t plain_len;
+	uint32_t iv_index;
+	uint32_t key_id;
+};
+
 static struct l_queue *beacons;
 static struct l_queue *keys;
 static uint32_t last_flooding_id;
@@ -255,6 +264,29 @@ static void decrypt_net_pkt(void *a, void *b)
 	}
 }
 
+static void decrypt_proxy_cfg_msg(void *a, void *b)
+{
+	const struct net_key *key = a;
+	struct proxy_cfg_msg *proxy_cfg = b;
+	bool result;
+
+	if (proxy_cfg->key_id || !key->ref_cnt ||
+					(proxy_cfg->data[0] & 0x7f) != key->nid)
+		return;
+
+	result = mesh_crypto_packet_decode(proxy_cfg->data, proxy_cfg->len,
+							true,
+							proxy_cfg->plain,
+							proxy_cfg->iv_index,
+							key->enc_key,
+							key->prv_key);
+
+	if (result) {
+		proxy_cfg->key_id = key->id;
+		proxy_cfg->plain_len = proxy_cfg->len;
+	}
+}
+
 uint32_t net_key_decrypt(uint32_t iv_index, const uint8_t *pkt, size_t len,
 					uint8_t **plain, size_t *plain_len)
 {
@@ -284,6 +316,30 @@ done:
 	return cache_id;
 }
 
+uint32_t net_key_decrypt_proxy_cfg_msg(uint32_t iv_index,
+					const uint8_t *pkt, size_t len,
+					uint8_t *plain, size_t *plain_len)
+{
+	struct proxy_cfg_msg proxy_cfg = {
+		.data = pkt,
+		.len = len,
+		.plain = plain,
+		.iv_index = iv_index,
+	};
+
+	/* MshPRT_v1.1, section 6.6: Proxy configuration messages have CTL=1 */
+	if (!(pkt[1] & CTL))
+		return 0;
+
+	/* Try all network keys known to us */
+	l_queue_foreach(keys, decrypt_proxy_cfg_msg, &proxy_cfg);
+
+	if (proxy_cfg.key_id)
+		*plain_len = proxy_cfg.plain_len;
+
+	return proxy_cfg.key_id;
+}
+
 bool net_key_encrypt(uint32_t id, uint32_t iv_index, uint8_t *pkt, size_t len)
 {
 	struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id));
diff --git a/mesh/net-keys.h b/mesh/net-keys.h
index 512347521547..b43157df29bc 100644
--- a/mesh/net-keys.h
+++ b/mesh/net-keys.h
@@ -26,6 +26,9 @@ uint32_t net_key_frnd_add(uint32_t flooding_id, uint16_t lpn, uint16_t frnd,
 void net_key_unref(uint32_t id);
 uint32_t net_key_decrypt(uint32_t iv_index, const uint8_t *pkt, size_t len,
 					uint8_t **plain, size_t *plain_len);
+uint32_t net_key_decrypt_proxy_cfg_msg(uint32_t iv_index,
+					const uint8_t *pkt, size_t len,
+					uint8_t *plain, size_t *plain_len);
 bool net_key_encrypt(uint32_t id, uint32_t iv_index, uint8_t *pkt, size_t len);
 uint32_t net_key_network_id(const uint8_t network[8]);
 uint32_t net_key_beacon(const uint8_t *data, uint16_t len, uint32_t *ivi,
diff --git a/mesh/net.c b/mesh/net.c
index 911f781ef75c..9a04aa5120c4 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -27,6 +27,7 @@
 #include "mesh/net-keys.h"
 #include "mesh/node.h"
 #include "mesh/net.h"
+#include "mesh/proxy-cfg.h"
 #include "mesh/mesh-io.h"
 #include "mesh/friend.h"
 #include "mesh/gatt-service.h"		// PROXY_MSG_TYPE_NETWORK_PDU
@@ -192,8 +193,20 @@ struct net_queue_data {
 	bool seen;
 };
 
+struct net_queue_data_proxy_cfg {
+	struct gatt_proxy_svc *gatt_proxy;
+	struct mesh_net *net;
+	const uint8_t *data;
+	uint8_t *out;
+	size_t out_size;
+	uint32_t net_key_id;
+	uint32_t iv_index;
+	uint16_t len;
+};
+
 struct oneshot_tx {
 	struct mesh_net *net;
+	uint16_t net_dst;
 	uint16_t interval;
 	bool frnd;
 	uint8_t cnt;
@@ -2303,17 +2316,20 @@ static void send_msg_pkt_oneshot(void *user_data)
 	 */
 	mesh_io_send(net->io, &info, tx->packet, tx->size);
 	if (!tx->frnd)
-		gatt_proxy_svc_send_net(tx->packet + 1, tx->size - 1);
+		gatt_proxy_svc_send_net(tx->net_dst, tx->packet + 1,
+								tx->size - 1);
 	l_free(tx);
 }
 
-static void send_msg_pkt(struct mesh_net *net, uint8_t cnt, uint16_t interval,
+static void send_msg_pkt(struct mesh_net *net, uint16_t dst, uint8_t cnt,
+					uint16_t interval,
 					const uint8_t *packet, uint8_t size,
 								bool frnd)
 {
 	struct oneshot_tx *tx = l_new(struct oneshot_tx, 1);
 
 	tx->net = net;
+	tx->net_dst = dst;
 	tx->interval = interval;
 	tx->frnd = frnd;
 	tx->cnt = cnt;
@@ -2324,6 +2340,7 @@ static void send_msg_pkt(struct mesh_net *net, uint8_t cnt, uint16_t interval,
 }
 
 static enum _relay_advice packet_received(struct mesh_net *net,
+				struct gatt_proxy_svc *gatt_proxy,
 				uint32_t net_key_id, uint16_t net_idx,
 				bool frnd, uint32_t iv_index,
 				const uint8_t *data, uint8_t size, int8_t rssi)
@@ -2347,7 +2364,9 @@ static enum _relay_advice packet_received(struct mesh_net *net,
 		return RELAY_NONE;
 	}
 
-	if (net_dst == 0) {
+	gatt_proxy_svc_filter_pdu_rcvd(gatt_proxy, net_src);
+
+	if (net_dst == UNASSIGNED_ADDRESS) {
 		l_error("illegal parms: DST: %4.4x Ctl: %d TTL: %2.2x",
 						net_dst, net_ctl, net_ttl);
 		return RELAY_NONE;
@@ -2508,7 +2527,8 @@ static void net_rx(void *net_ptr, void *user_data)
 	if (data->gatt_proxy && frnd)
 		return;
 
-	relay_advice = packet_received(net, net_key_id, net_idx, frnd,
+	relay_advice = packet_received(net, data->gatt_proxy, net_key_id,
+						net_idx, frnd,
 						iv_index, out, out_size, rssi);
 	if (relay_advice > data->relay_advice) {
 		/*
@@ -2527,6 +2547,48 @@ static void net_rx(void *net_ptr, void *user_data)
 	}
 }
 
+static void net_proxy_cfg_msg_rx(void *net_ptr, void *user_data)
+{
+	struct net_queue_data_proxy_cfg *data = user_data;
+	struct mesh_net *net = net_ptr;
+	uint8_t out[MESH_NET_MAX_PDU_LEN];
+	size_t out_size;
+	uint32_t net_key_id;
+	uint16_t net_idx;
+	bool frnd;
+	bool ivi_net = !!(net->iv_index & 1);
+	bool ivi_pkt = !!(data->data[0] & 0x80);
+
+	/* if IVI flag differs, use previous IV Index */
+	uint32_t iv_index = net->iv_index - (ivi_pkt ^ ivi_net);
+
+	net_key_id = net_key_decrypt_proxy_cfg_msg(iv_index,
+							data->data, data->len,
+							out, &out_size);
+
+	if (!net_key_id)
+		return;
+
+	net_idx = key_id_to_net_idx(net, net_key_id, &frnd);
+
+	if (net_idx == NET_IDX_INVALID)
+		return;
+
+	/*
+	 * MshPRT_v1.1, section 3.4.5.1 - Interface input filter
+	 * The input filter of the interface connected to the GATT bearer shall
+	 * drop all Network PDUs that have been secured using the friendship
+	 * security credentials.
+	 */
+	if (frnd)
+		return;
+
+	print_packet("RX: ProxyCfg [enc] :", data->data, data->len);
+
+	proxy_cfg_msg_received(data->gatt_proxy, net, net_key_id, iv_index, out,
+								out_size);
+}
+
 static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info,
 					const uint8_t *data, uint16_t len)
 {
@@ -2566,6 +2628,25 @@ static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info,
 	}
 }
 
+static void
+net_proxy_cfg_msg_recv(void *user_data, struct mesh_io_recv_info *info,
+					const uint8_t *data, uint16_t len)
+{
+	struct gatt_proxy_svc *gatt_proxy = user_data;
+	struct net_queue_data_proxy_cfg net_data = {
+		.gatt_proxy = gatt_proxy,
+		.data = data + 1,
+		.len = len - 1,
+	};
+
+	if (len < 9)
+		return;
+
+	l_queue_foreach(nets, net_proxy_cfg_msg_rx, &net_data);
+
+	/* Proxy configuration messages are not relayed */
+}
+
 static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data)
 {
 	struct mesh_net *net = user_data;
@@ -3080,6 +3161,9 @@ void mesh_net_attach_gatt(struct gatt_proxy_svc *gatt_proxy)
 	gatt_proxy_svc_register_recv_cb(gatt_proxy, PROXY_MSG_TYPE_NETWORK_PDU,
 							net_msg_recv,
 							gatt_proxy);
+	gatt_proxy_svc_register_recv_cb(gatt_proxy, PROXY_MSG_TYPE_PROXY_CFG,
+							net_proxy_cfg_msg_recv,
+							gatt_proxy);
 }
 
 void mesh_net_detach_gatt(struct gatt_proxy_svc *gatt_proxy)
@@ -3088,6 +3172,8 @@ void mesh_net_detach_gatt(struct gatt_proxy_svc *gatt_proxy)
 
 	gatt_proxy_svc_deregister_recv_cb(gatt_proxy,
 						PROXY_MSG_TYPE_NETWORK_PDU);
+	gatt_proxy_svc_deregister_recv_cb(gatt_proxy,
+						PROXY_MSG_TYPE_PROXY_CFG);
 }
 
 bool mesh_net_iv_index_update(struct mesh_net *net)
@@ -3214,8 +3300,8 @@ static bool send_seg(struct mesh_net *net, uint8_t cnt, uint16_t interval,
 		return false;
 	}
 
-	send_msg_pkt(net, cnt, interval, packet, packet_len + 1, false);
-
+	send_msg_pkt(net, msg->remote, cnt, interval, packet, packet_len + 1,
+									false);
 	msg->last_seg = segO;
 
 	return true;
@@ -3268,7 +3354,7 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id,
 		return;
 	}
 
-	send_msg_pkt(net, net->tx_cnt, net->tx_interval, packet,
+	send_msg_pkt(net, dst, net->tx_cnt, net->tx_interval, packet,
 							packet_len + 1, frnd);
 
 	l_debug("TX: Friend Seg-%d %04x -> %04x : len %u) : TTL %d : SEQ %06x",
@@ -3433,7 +3519,7 @@ void mesh_net_ack_send(struct mesh_net *net, uint32_t net_key_id,
 		return;
 	}
 
-	send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt, pkt_len + 1,
+	send_msg_pkt(net, dst, net->tx_cnt, net->tx_interval, pkt, pkt_len + 1,
 									frnd);
 
 	l_debug("TX: Friend ACK %04x -> %04x : len %u : TTL %d : SEQ %06x",
@@ -3522,7 +3608,7 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t net_key_id,
 	}
 
 	if (!(IS_UNASSIGNED(dst)))
-		send_msg_pkt(net, net->tx_cnt, net->tx_interval, pkt,
+		send_msg_pkt(net, dst, net->tx_cnt, net->tx_interval, pkt,
 							pkt_len + 1, frnd);
 }
 
diff --git a/mesh/proxy-cfg.c b/mesh/proxy-cfg.c
new file mode 100644
index 000000000000..5a9439f4d941
--- /dev/null
+++ b/mesh/proxy-cfg.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2025  ARRI Lighting. All rights reserved.
+ *
+ *
+ */
+
+#include <stdbool.h>
+
+#include <ell/dbus.h>
+#include <ell/log.h>
+#include <ell/util.h>			// l_get_be16(), l_put_be16()
+
+#include "src/shared/ad.h"
+
+#include "mesh/crypto.h"		// mesh_crypto_network_header_parse()
+#include "mesh/mesh-io.h"		// mesh_io_recv_func_t, required by gatt-proxy-svc.h
+#include "mesh/gatt-proxy-svc.h"	// gatt_proxy_svc_filter_set_type(),
+					// gatt_proxy_svc_filter_add(),
+					// gatt_proxy_svc_filter_remove(),
+					// gatt_proxy_svc_filter_count(),
+					// gatt_proxy_svc_send()
+#include "mesh/mesh-defs.h"		// UNASSIGNED_ADDRESS
+#include "mesh/net.h"			// PROXY_OP_SET_FILTER_TYPE,
+					// PROXY_OP_FILTER_ADD,
+					// PROXY_OP_FILTER_DEL,
+					// PROXY_OP_FILTER_STATUS,
+					// mesh_net_next_seq_num(),
+					// mesh_net_get_address()
+#include "mesh/net-keys.h"		// net_key_encrypt(),
+					// net_key_decrypt_proxy_cfg_msg()
+#include "mesh/util.h"			// print_packet()
+#include "mesh/proxy-cfg.h"
+
+void proxy_cfg_msg_received(struct gatt_proxy_svc *gatt_proxy,
+					struct mesh_net *net,
+					uint32_t net_key_id, uint32_t iv_index,
+					const uint8_t *data, uint8_t size)
+{
+	const uint8_t *msg;
+	uint8_t cfg_msg_len;
+	uint8_t net_ttl;
+	uint32_t net_seq;
+	uint16_t net_src, net_dst;
+	bool net_ctl;
+	uint8_t rsp[4];  // length of PROXY_OP_FILTER_STATUS
+	uint8_t rsp_len = 0;
+
+	print_packet("RX: ProxyCfg [clr] :", data, size);
+
+	if (!mesh_crypto_network_header_parse(data, size, &net_ctl, &net_ttl,
+					&net_seq, &net_src, &net_dst)) {
+		l_error("Failed to parse packet content");
+		return;
+	}
+
+	/*
+	 * MshPRT_v1.1, section 6.6:
+	 * - The CTL field shall be set to 1. [already checked]
+	 * - The TTL field shall be set to 0.
+	 * - The DST field shall be set to the unassigned address.
+	 */
+	if (net_dst != UNASSIGNED_ADDRESS || net_ttl) {
+		l_error("illegal parms: DST: %4.4x Ctl: %d TTL: %2.2x",
+						net_dst, net_ctl, net_ttl);
+		return;
+	}
+
+	l_debug("RX: ProxyCfg %04x -> %04x : TTL 0x%02x : IV : %8.8x SEQ 0x%06x",
+			net_src, net_dst, net_ttl, iv_index, net_seq);
+
+	msg = data + 9;
+	cfg_msg_len = size - 9 - 8 /* NetMIC */;
+
+	if (!cfg_msg_len)
+		return;
+
+	/* process request */
+	switch (msg[0]) {
+		case PROXY_OP_SET_FILTER_TYPE:
+			if (cfg_msg_len >= 2) {
+				uint8_t filter_type;
+
+				filter_type = msg[1];
+				gatt_proxy_svc_filter_set_type(gatt_proxy,
+								filter_type);
+			}
+			break;
+
+		case PROXY_OP_FILTER_ADD:
+			if (cfg_msg_len & 0x1) {
+				int num_filters = (cfg_msg_len - 1) / 2, i;
+				uint16_t addr;
+
+				for (i = 0; i < num_filters; i++) {
+					addr = l_get_be16(msg + 2 * i + 1);
+					gatt_proxy_svc_filter_add(gatt_proxy,
+									addr);
+				}
+			}
+			break;
+
+		case PROXY_OP_FILTER_DEL:
+			if (cfg_msg_len & 0x1) {
+				int num_filters = (cfg_msg_len - 1) / 2, i;
+				uint16_t addr;
+
+				for (i = 0; i < num_filters; i++) {
+					addr = l_get_be16(msg + 2 * i + 1);
+					gatt_proxy_svc_filter_remove(gatt_proxy,
+									addr);
+				}
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	/* prepare response */
+	switch (msg[0]) {
+		case PROXY_OP_SET_FILTER_TYPE:
+		case PROXY_OP_FILTER_ADD:
+		case PROXY_OP_FILTER_DEL: {
+			uint8_t filter_type;
+			uint16_t num_filters =
+				gatt_proxy_svc_filter_count(gatt_proxy,
+								&filter_type);
+			rsp[0] = PROXY_OP_FILTER_STATUS;
+			rsp[1] = filter_type;
+			l_put_be16(num_filters, &rsp[2]);
+			rsp_len = 4;
+			break;
+		}
+
+		/*
+		 * MshPRT_v1.1, section 6.7:
+		 * Upon receiving a proxy configuration message with the Opcode
+		 * field set to a value that is Reserved for Future Use, the
+		 * Proxy Server shall ignore this message.
+		 */
+		default:
+			break;
+	}
+
+	if (rsp_len) {
+		uint8_t pkt[MESH_NET_MAX_PDU_LEN];
+		uint8_t pkt_len;
+
+		net_seq = mesh_net_next_seq_num(net);
+		if (!mesh_crypto_packet_build(true, 0/*TTL*/, net_seq,
+					mesh_net_get_address(net)/*src*/,
+					UNASSIGNED_ADDRESS/*dst*/, rsp[0],
+					false, 0, false, 0, 0, 0,
+					rsp + 1, rsp_len - 1, pkt, &pkt_len))
+			return;
+
+		if (!net_key_encrypt(net_key_id, iv_index, pkt, pkt_len)) {
+			l_error("Failed to encode packet");
+			return;
+		}
+
+		gatt_proxy_svc_send_proxy_cfg(pkt, pkt_len);
+	}
+}
diff --git a/mesh/proxy-cfg.h b/mesh/proxy-cfg.h
new file mode 100644
index 000000000000..b41cbd512c05
--- /dev/null
+++ b/mesh/proxy-cfg.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  ARRI Lighting. All rights reserved.
+ *
+ *
+ */
+
+#include <stdint.h>
+
+struct gatt_proxy_svc;
+struct mesh_net;
+
+void proxy_cfg_msg_received(struct gatt_proxy_svc *gatt_proxy,
+					struct mesh_net *net,
+					uint32_t net_key_id, uint32_t iv_index,
+					const uint8_t *data, uint8_t size);
-- 
2.43.0





[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux