
Adds a simple, tracepoint inspired hook definiton framework to centralize all calls to rmnet support modules. Modules can set and unset these hooks freely, and modules may call one another's hooks without being forced to link against any module other than the core rmnet module. Change-Id: I949f7a17c95003e0c79262c6611b0602c7189e0c Signed-off-by: Sean Tranchetti <quic_stranche@quicinc.com>
101 lines
2.6 KiB
C
101 lines
2.6 KiB
C
/* 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"
|
|
|