Эх сурвалжийг харах

Merge "rmnet_core: Add generic module framework"

qctecmdr 3 жил өмнө
parent
commit
6d889c5e92
5 өөрчлөгдсөн 340 нэмэгдсэн , 0 устгасан
  1. 1 0
      core/Kbuild
  2. 1 0
      core/Makefile
  3. 108 0
      core/rmnet_hook.h
  4. 100 0
      core/rmnet_module.c
  5. 130 0
      core/rmnet_module.h

+ 1 - 0
core/Kbuild

@@ -16,6 +16,7 @@ rmnet_core-y := \
 	rmnet_genl.o \
 	rmnet_map_command.o \
 	rmnet_map_data.o \
+	rmnet_module.o \
 	rmnet_vnd.o
 
 rmnet_core-y += \

+ 1 - 0
core/Makefile

@@ -18,6 +18,7 @@ rmnet_core-y += 	rmnet_config.o \
 			rmnet_handlers.o \
 			rmnet_map_command.o \
 			rmnet_map_data.o \
+			rmnet_module.o \
 			rmnet_vnd.o \
 			dfc_qmap.c \
 			dfc_qmi.c \

+ 108 - 0
core/rmnet_hook.h

@@ -0,0 +1,108 @@
+/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#if !defined(__RMNET_HOOKS__) || defined(__RMNET_HOOK_MULTIREAD__)
+#define __RMNET_HOOKS__
+
+#include <linux/skbuff.h>
+#include <linux/tcp.h>
+#include "rmnet_descriptor.h"
+
+RMNET_MODULE_HOOK(offload_ingress,
+	RMNET_MODULE_HOOK_NUM(OFFLOAD_INGRESS),
+	RMNET_MODULE_HOOK_PROTOCOL(struct list_head *desc_list,
+				   struct rmnet_port *port),
+	RMNET_MODULE_HOOK_ARGS(desc_list, port),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(offload_chain_end,
+	RMNET_MODULE_HOOK_NUM(OFFLOAD_CHAIN_END),
+	RMNET_MODULE_HOOK_PROTOCOL(void),
+	RMNET_MODULE_HOOK_ARGS(),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(shs_skb_entry,
+	RMNET_MODULE_HOOK_NUM(SHS_SKB_ENTRY),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb,
+				   struct rmnet_shs_clnt_s *cfg),
+	RMNET_MODULE_HOOK_ARGS(skb, cfg),
+	RMNET_MODULE_HOOK_RETURN_TYPE(int)
+);
+
+RMNET_MODULE_HOOK(shs_switch,
+	RMNET_MODULE_HOOK_NUM(SHS_SWITCH),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb,
+				   struct rmnet_shs_clnt_s *cfg),
+	RMNET_MODULE_HOOK_ARGS(skb, cfg),
+	RMNET_MODULE_HOOK_RETURN_TYPE(int)
+);
+
+RMNET_MODULE_HOOK(perf_tether_ingress,
+	RMNET_MODULE_HOOK_NUM(PERF_TETHER_INGRESS),
+	RMNET_MODULE_HOOK_PROTOCOL(struct tcphdr *tp,
+				   struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(tp, skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(perf_tether_egress,
+	RMNET_MODULE_HOOK_NUM(PERF_TETHER_EGRESS),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(perf_tether_cmd,
+	RMNET_MODULE_HOOK_NUM(PERF_TETHER_CMD),
+	RMNET_MODULE_HOOK_PROTOCOL(u8 message, u64 val),
+	RMNET_MODULE_HOOK_ARGS(message, val),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(perf_ingress,
+	RMNET_MODULE_HOOK_NUM(PERF_INGRESS),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(int)
+);
+
+RMNET_MODULE_HOOK(perf_egress,
+	RMNET_MODULE_HOOK_NUM(PERF_EGRESS),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(aps_pre_queue,
+	RMNET_MODULE_HOOK_NUM(APS_PRE_QUEUE),
+	RMNET_MODULE_HOOK_PROTOCOL(struct net_device *dev, struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(dev, skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+RMNET_MODULE_HOOK(aps_post_queue,
+	RMNET_MODULE_HOOK_NUM(APS_POST_QUEUE),
+	RMNET_MODULE_HOOK_PROTOCOL(struct net_device *dev, struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(dev, skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(int)
+);
+
+RMNET_MODULE_HOOK(wlan_flow_match,
+	RMNET_MODULE_HOOK_NUM(WLAN_FLOW_MATCH),
+	RMNET_MODULE_HOOK_PROTOCOL(struct sk_buff *skb),
+	RMNET_MODULE_HOOK_ARGS(skb),
+	RMNET_MODULE_HOOK_RETURN_TYPE(void)
+);
+
+#endif

+ 100 - 0
core/rmnet_module.c

@@ -0,0 +1,100 @@
+/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "rmnet_module.h"
+
+struct rmnet_module_hook_info {
+	void *func __rcu;
+};
+
+static struct rmnet_module_hook_info
+rmnet_module_hooks[__RMNET_MODULE_NUM_HOOKS];
+
+void
+rmnet_module_hook_register(const struct rmnet_module_hook_register_info *info,
+			   int hook_count)
+{
+	struct rmnet_module_hook_info *hook_info;
+	int i;
+
+	for (i = 0; i < hook_count; i++) {
+		int hook = info[i].hooknum;
+
+		if (hook < __RMNET_MODULE_NUM_HOOKS) {
+			hook_info = &rmnet_module_hooks[hook];
+			rcu_assign_pointer(hook_info->func, info[i].func);
+		}
+	}
+}
+EXPORT_SYMBOL(rmnet_module_hook_register);
+
+bool rmnet_module_hook_is_set(int hook)
+{
+	if (hook >= __RMNET_MODULE_NUM_HOOKS)
+		return false;
+
+	return rcu_dereference(rmnet_module_hooks[hook].func) != NULL;
+}
+EXPORT_SYMBOL(rmnet_module_hook_is_set);
+
+void
+rmnet_module_hook_unregister_no_sync(const struct rmnet_module_hook_register_info *info,
+				     int hook_count)
+{
+	struct rmnet_module_hook_info *hook_info;
+	int i;
+
+	for (i = 0; i < hook_count; i++) {
+		int hook = info[i].hooknum;
+
+		if (hook < __RMNET_MODULE_NUM_HOOKS) {
+			hook_info = &rmnet_module_hooks[hook];
+			rcu_assign_pointer(hook_info->func, NULL);
+		}
+	}
+}
+EXPORT_SYMBOL(rmnet_module_hook_unregister_no_sync);
+
+#define __RMNET_HOOK_DEFINE(call, hook_num, proto, args, ret_type) \
+int rmnet_module_hook_##call( \
+__RMNET_HOOK_PROTO(RMNET_HOOK_PARAMS(proto), ret_type) \
+) \
+{ \
+	ret_type (*__func)(proto); \
+	struct rmnet_module_hook_info *__info = \
+		&rmnet_module_hooks[hook_num]; \
+	int __ret = 0; \
+\
+	rcu_read_lock(); \
+	__func = rcu_dereference(__info->func); \
+	if (__func) { \
+		RMNET_HOOK_IF_NON_VOID_TYPE(ret_type)( ret_type __rc = ) \
+		__func(args); \
+		__ret = 1; \
+\
+		RMNET_HOOK_IF_NON_VOID_TYPE(ret_type)( if (__ret_code) \
+			*__ret_code = __rc; )\
+	} \
+\
+	rcu_read_unlock(); \
+	return __ret; \
+} \
+EXPORT_SYMBOL(rmnet_module_hook_##call);
+
+#undef RMNET_MODULE_HOOK
+#define RMNET_MODULE_HOOK(call, hook_num, proto, args, ret_type) \
+__RMNET_HOOK_DEFINE(call, hook_num, RMNET_HOOK_PARAMS(proto), \
+		    RMNET_HOOK_PARAMS(args), ret_type)
+
+#define __RMNET_HOOK_MULTIREAD__
+#include "rmnet_hook.h"
+

+ 130 - 0
core/rmnet_module.h

@@ -0,0 +1,130 @@
+/* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef __RMNET_MODULE_H__
+#define __RMNET_MODULE_H__
+
+#include <linux/rcupdate.h>
+
+enum {
+	RMNET_MODULE_HOOK_OFFLOAD_INGRESS,
+	RMNET_MODULE_HOOK_OFFLOAD_CHAIN_END,
+	RMNET_MODULE_HOOK_SHS_SKB_ENTRY,
+	RMNET_MODULE_HOOK_SHS_SWITCH,
+	RMNET_MODULE_HOOK_PERF_TETHER_INGRESS,
+	RMNET_MODULE_HOOK_PERF_TETHER_EGRESS,
+	RMNET_MODULE_HOOK_PERF_TETHER_CMD,
+	RMNET_MODULE_HOOK_PERF_INGRESS,
+	RMNET_MODULE_HOOK_PERF_EGRESS,
+	RMNET_MODULE_HOOK_APS_PRE_QUEUE,
+	RMNET_MODULE_HOOK_APS_POST_QUEUE,
+	RMNET_MODULE_HOOK_WLAN_FLOW_MATCH,
+	__RMNET_MODULE_NUM_HOOKS,
+};
+
+struct rmnet_module_hook_register_info {
+	int hooknum;
+	void *func;
+};
+
+void
+rmnet_module_hook_register(const struct rmnet_module_hook_register_info *info,
+			   int hook_count);
+bool rmnet_module_hook_is_set(int hook);
+void
+rmnet_module_hook_unregister_no_sync(const struct rmnet_module_hook_register_info *info,
+				     int hook_count);
+static inline void
+rmnet_module_hook_unregister(const struct rmnet_module_hook_register_info *info,
+			     int hook_count)
+{
+	rmnet_module_hook_unregister_no_sync(info, hook_count);
+	synchronize_rcu();
+}
+
+/* Dummy macro. Can use kernel version later */
+#define __CAT(a, b) a ## b
+#define CAT(a, b) __CAT(a, b)
+
+#define RMNET_HOOK_PARAMS(args...) args
+
+#define RMNET_MODULE_HOOK_NUM(__hook) CAT(RMNET_MODULE_HOOK_, __hook)
+#define RMNET_MODULE_HOOK_PROTOCOL(proto...) proto
+#define RMNET_MODULE_HOOK_ARGS(args...) args
+#define RMNET_MODULE_HOOK_RETURN_TYPE(type) type
+
+/* A ...lovely... framework for checking if the argument passed in to a function
+ * macro is a pair of parentheses.
+ * If so, resolve to 1. Otherwise, 0.
+ *
+ * The idea here is that you pass the argument along with a "test" macro to
+ * a "checker" macro. If the argument IS a pair of parentheses, this will cause
+ * the tester macro to expand into multiple arguments.
+ *
+ * The key is that "checker" macro just returns the second argument it receives.
+ * So have the "tester" macro expand to a set of arguments that makes 1 the
+ * second argument, or 0 if it doesn't expand.
+ */
+#define __RMNET_HOOK_SECOND_ARG(_, arg, ...) arg
+#define RMNET_HOOK_PARENTHESES_CHECKER(args...) \
+	__RMNET_HOOK_SECOND_ARG(args, 0, )
+#define __RMNET_HOOK_PARENTHESES_TEST(arg) arg, 1,
+#define __RMNET_HOOK_IS_PARENTHESES_TEST(...) __RMNET_HOOK_PARENTHESES_TEST(XXX)
+#define RMNET_HOOK_IS_PARENTHESES(arg) \
+	RMNET_HOOK_PARENTHESES_CHECKER(__RMNET_HOOK_IS_PARENTHESES_TEST arg)
+
+/* So what's the point of the above stuff, you ask?
+ *
+ * CPP can't actually do type checking ;). But what we CAN do is something
+ * like this to determine if the type passed in is void. If so, this will
+ * expand to (), causing the RMNET_HOOK_IS_PARENTHESES check to resolve to 1,
+ * but if not, then the check resolves to 0.
+ */
+#define __RMNET_HOOK_CHECK_TYPE_IS_void(arg) arg
+#define RMNET_HOOK_TYPE_IS_VOID(type) \
+	RMNET_HOOK_IS_PARENTHESES( __RMNET_HOOK_CHECK_TYPE_IS_ ## type (()) )
+
+/* And now, we have some logic macros. The main macro will resolve
+ * to one of the branches depending on the bool value passed in.
+ */
+#define __IF_0(t_path, e_path...) e_path
+#define __IF_1(t_path, e_path...) t_path
+#define IF(arg) CAT(__IF_, arg)
+#define __NOT_1 0
+#define __NOT_0 1
+#define NOT(arg) CAT(__NOT_, arg)
+
+/* And now we combine this all, for a purely function macro way of splitting
+ * return type handling...
+ *
+ * ...all to circumvent that you can't actually add #if conditionals in macro
+ * expansions. It would have been much simpler that way. ;)
+ */
+#define RMNET_HOOK_IF_NON_VOID_TYPE(type) \
+	IF(NOT(RMNET_HOOK_TYPE_IS_VOID(type)))
+
+#define __RMNET_HOOK_PROTO(proto, ret_type)\
+RMNET_HOOK_IF_NON_VOID_TYPE(ret_type) \
+	(RMNET_HOOK_PARAMS(ret_type *__ret_code, proto), \
+	 RMNET_HOOK_PARAMS(proto))
+
+#define __RMNET_HOOK_DECLARE(call, proto, ret_type) \
+int rmnet_module_hook_##call( \
+__RMNET_HOOK_PROTO(RMNET_HOOK_PARAMS(proto), ret_type));
+
+#undef RMNET_MODULE_HOOK
+#define RMNET_MODULE_HOOK(call, hook_num, proto, args, ret_type) \
+__RMNET_HOOK_DECLARE(call, RMNET_HOOK_PARAMS(proto), ret_type)
+
+#include "rmnet_hook.h"
+
+#endif