diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 0d9459b6..b0e1b73c 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -378,7 +378,8 @@ batadv_netlink_tp_meter_start(struct sk_buff *skb, struct genl_info *info)
 	}
 
 	bat_priv = netdev_priv(soft_iface);
-	batadv_tp_start(bat_priv, dst, test_length, &cookie);
+	batadv_tp_start(bat_priv, dst, test_length, &cookie,
+			BATADV_TP_USERSPACE);
 
 	ret = batadv_netlink_tp_meter_put(msg, cookie);
 
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index 73f7f168..1f201ec7 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -215,50 +215,71 @@ static void batadv_tp_update_rto(struct batadv_tp_vars *tp_vars,
 }
 
 /**
- * batadv_tp_batctl_notify() - send client status result to client
- * @reason: reason for tp meter session stop
- * @dst: destination of tp_meter session
+ * batadv_tp_caller_notify() - send tp meter status result to caller
  * @bat_priv: the bat priv with all the soft interface information
- * @start_time: start of transmission in jiffies
- * @total_sent: bytes acked to the receiver
- * @cookie: cookie of tp_meter session
+ * @tp_vars: the private data of the current TP meter session
+ * @reason: reason for tp meter session stop
  */
-static void batadv_tp_batctl_notify(enum batadv_tp_meter_reason reason,
-				    const u8 *dst, struct batadv_priv *bat_priv,
-				    unsigned long start_time, u64 total_sent,
-				    u32 cookie)
+static void batadv_tp_caller_notify(struct batadv_priv *bat_priv,
+				    struct batadv_tp_vars *tp_vars,
+				    enum batadv_tp_meter_reason reason)
 {
-	u32 test_time;
-	u8 result;
 	u32 total_bytes;
+	u32 test_time;
+	u32 cookie;
+	bool reason_is_error;
 
-	if (!batadv_tp_is_error(reason)) {
-		result = BATADV_TP_REASON_COMPLETE;
-		test_time = jiffies_to_msecs(jiffies - start_time);
-		total_bytes = total_sent;
-	} else {
-		result = reason;
-		test_time = 0;
-		total_bytes = 0;
-	}
+	reason_is_error = batadv_tp_is_error(reason);
+
+	switch (tp_vars->caller) {
+	case BATADV_TP_USERSPACE:
+		cookie = batadv_tp_session_cookie(tp_vars->session,
+						  tp_vars->icmp_uid);
+
+		if (reason_is_error) {
+			batadv_netlink_tpmeter_notify(bat_priv,
+						      tp_vars->other_end,
+						      reason, 0, 0, cookie);
+			return;
+		}
+
+		test_time = jiffies_to_msecs(jiffies - tp_vars->start_time);
+		total_bytes = atomic64_read(&tp_vars->tot_sent);
+		batadv_netlink_tpmeter_notify(bat_priv, tp_vars->other_end,
+					      BATADV_TP_REASON_COMPLETE,
+					      test_time, total_bytes, cookie);
 
-	batadv_netlink_tpmeter_notify(bat_priv, dst, result, test_time,
-				      total_bytes, cookie);
+		break;
+	case BATADV_TP_ELP:
+		break;
+	default:
+		break;
+	}
 }
 
 /**
- * batadv_tp_batctl_error_notify() - send client error result to client
+ * batadv_tp_caller_init_error() - report early tp meter errors to caller
+ * @bat_priv: the bat priv with all the soft interface information
+ * @caller: caller of tp meter session (user space or ELP)
  * @reason: reason for tp meter session stop
  * @dst: destination of tp_meter session
- * @bat_priv: the bat priv with all the soft interface information
  * @cookie: cookie of tp_meter session
  */
-static void batadv_tp_batctl_error_notify(enum batadv_tp_meter_reason reason,
-					  const u8 *dst,
-					  struct batadv_priv *bat_priv,
-					  u32 cookie)
+static void batadv_tp_caller_init_error(struct batadv_priv *bat_priv,
+					enum batadv_tp_meter_caller caller,
+					enum batadv_tp_meter_reason reason,
+					const u8 *dst, u32 cookie)
 {
-	batadv_tp_batctl_notify(reason, dst, bat_priv, 0, 0, cookie);
+	switch (caller) {
+	case BATADV_TP_USERSPACE:
+		batadv_netlink_tpmeter_notify(bat_priv, dst, reason, 0, 0,
+					      cookie);
+		break;
+	case BATADV_TP_ELP:
+		break;
+	default:
+		break;
+	}
 }
 
 /**
@@ -411,8 +432,6 @@ static void batadv_tp_sender_cleanup(struct batadv_priv *bat_priv,
 static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
 				 struct batadv_tp_vars *tp_vars)
 {
-	u32 session_cookie;
-
 	batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
 		   "Test towards %pM finished..shutting down (reason=%d)\n",
 		   tp_vars->other_end, tp_vars->reason);
@@ -425,15 +444,7 @@ static void batadv_tp_sender_end(struct batadv_priv *bat_priv,
 		   "Final values: cwnd=%u ss_threshold=%u\n",
 		   tp_vars->cwnd, tp_vars->ss_threshold);
 
-	session_cookie = batadv_tp_session_cookie(tp_vars->session,
-						  tp_vars->icmp_uid);
-
-	batadv_tp_batctl_notify(tp_vars->reason,
-				tp_vars->other_end,
-				bat_priv,
-				tp_vars->start_time,
-				atomic64_read(&tp_vars->tot_sent),
-				session_cookie);
+	batadv_tp_caller_notify(bat_priv, tp_vars, tp_vars->reason);
 }
 
 /**
@@ -914,9 +925,11 @@ static void batadv_tp_send(struct work_struct *work)
  * @dst: the receiver MAC address
  * @test_length: test length in milliseconds
  * @cookie: session cookie
+ * @caller: caller of tp meter session (user space or ELP)
  */
 void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
-		     u32 test_length, u32 *cookie)
+		     u32 test_length, u32 *cookie,
+		     enum batadv_tp_meter_caller caller)
 {
 	struct batadv_tp_vars *tp_vars;
 	u8 session_id[2];
@@ -932,15 +945,17 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
 	if (!atomic_add_unless(&bat_priv->tp_num, 1, BATADV_TP_MAX_NUM_QUEUE)) {
 		batadv_dbg(BATADV_DBG_TP_METER, bat_priv,
 			   "Meter: too many ongoing sessions, aborting (SEND)\n");
-		batadv_tp_batctl_error_notify(BATADV_TP_REASON_TOO_MANY, dst,
-					      bat_priv, session_cookie);
+		batadv_tp_caller_init_error(bat_priv, caller,
+					    BATADV_TP_REASON_TOO_MANY, dst,
+					    session_cookie);
 		return;
 	}
 
 	tp_vars = kmalloc(sizeof(*tp_vars), GFP_ATOMIC);
 	if (!tp_vars) {
-		batadv_tp_batctl_error_notify(BATADV_TP_REASON_MEMORY_ERROR,
-					      dst, bat_priv, session_cookie);
+		batadv_tp_caller_init_error(bat_priv, caller,
+					    BATADV_TP_REASON_MEMORY_ERROR, dst,
+					    session_cookie);
 		return;
 	}
 
@@ -948,6 +963,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
 	ether_addr_copy(tp_vars->other_end, dst);
 	kref_init(&tp_vars->refcount);
 	tp_vars->role = BATADV_TP_SENDER;
+	tp_vars->caller = caller;
 	atomic_set(&tp_vars->sending, 1);
 	memcpy(tp_vars->session, session_id, sizeof(session_id));
 	tp_vars->icmp_uid = icmp_uid;
diff --git a/net/batman-adv/tp_meter.h b/net/batman-adv/tp_meter.h
index ab0bde26..3b11a3e9 100644
--- a/net/batman-adv/tp_meter.h
+++ b/net/batman-adv/tp_meter.h
@@ -28,7 +28,8 @@ struct sk_buff;
 int batadv_tp_meter_init(void);
 void batadv_tp_meter_destroy(void);
 void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
-		     u32 test_length, u32 *cookie);
+		     u32 test_length, u32 *cookie,
+		     enum batadv_tp_meter_caller caller);
 void batadv_tp_stop(struct batadv_priv *bat_priv, const u8 *dst,
 		    u8 return_value);
 void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 2696b093..56034b54 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1324,6 +1324,16 @@ enum batadv_tp_meter_role {
 	BATADV_TP_SENDER
 };
 
+/**
+ * enum batadv_tp_meter_caller - initiator of the tp meter session
+ * @BATADV_TP_USERSPACE: initiated by user space
+ * @BATADV_TP_ELP: initiated by ELP
+ */
+enum batadv_tp_meter_caller {
+	BATADV_TP_USERSPACE,
+	BATADV_TP_ELP
+};
+
 /**
  * struct batadv_tp_vars - tp meter private variables per session
  */
@@ -1346,6 +1356,9 @@ struct batadv_tp_vars {
 	/** @role: receiver/sender modi */
 	enum batadv_tp_meter_role role;
 
+	/** @caller: caller of tp meter session (user space or ELP) */
+	enum batadv_tp_meter_caller caller;
+
 	/** @sending: sending binary semaphore: 1 if sending, 0 is not */
 	atomic_t sending;
 
