6db4831e98
Android 14
342 lines
7.5 KiB
C
342 lines
7.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* mddp_if.c - Interface API between MDDP and other kernel module.
|
|
*
|
|
* Copyright (c) 2020 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/netdevice.h>
|
|
|
|
#include "mddp_ctrl.h"
|
|
#include "mddp_debug.h"
|
|
#include "mddp_dev.h"
|
|
#include "mddp_filter.h"
|
|
#include "mddp_sm.h"
|
|
#include "mddp_usage.h"
|
|
|
|
#define MDDP_WIFI_NETIF_ID 0x500 /* copy from MD IPC_NETIF_ID_MCIF_BEGIN */
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Struct definition.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private helper macro.
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private variables.
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private helper macro.
|
|
//------------------------------------------------------------------------------
|
|
#define MDDP_CHECK_APP_TYPE(_type) \
|
|
((_type >= 0 && _type < MDDP_APP_TYPE_CNT) ? (1) : (0))
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Private functions.
|
|
//------------------------------------------------------------------------------
|
|
static uint32_t mddp_netdev_notifier_is_init;
|
|
static int mddp_netdev_notify_cb(struct notifier_block *nb,
|
|
unsigned long event, void *data)
|
|
{
|
|
struct mddp_app_t *app;
|
|
struct net_device *dev = netdev_notifier_info_to_dev(data);
|
|
|
|
if (!mddp_netdev_notifier_is_init)
|
|
return NOTIFY_DONE;
|
|
|
|
if (event == NETDEV_UNREGISTER) {
|
|
if (mddp_f_is_support_lan_dev(dev->ifindex) ||
|
|
mddp_f_is_support_wan_dev(dev->ifindex)) {
|
|
app = mddp_get_app_inst(MDDP_APP_TYPE_WH);
|
|
mddp_sm_on_event(app, MDDP_EVT_FUNC_DEACT);
|
|
}
|
|
}
|
|
|
|
return NOTIFY_DONE;
|
|
}
|
|
|
|
static struct notifier_block mddp_netdev_notifier __read_mostly = {
|
|
.notifier_call = mddp_netdev_notify_cb,
|
|
};
|
|
|
|
void mddp_netdev_notifier_init(void)
|
|
{
|
|
if (register_netdevice_notifier(&mddp_netdev_notifier) == 0)
|
|
mddp_netdev_notifier_is_init = 1;
|
|
}
|
|
|
|
void mddp_netdev_notifier_exit(void)
|
|
{
|
|
if (mddp_netdev_notifier_is_init) {
|
|
mddp_netdev_notifier_is_init = 0;
|
|
unregister_netdevice_notifier(&mddp_netdev_notifier);
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------------
|
|
// Public functions.
|
|
//------------------------------------------------------------------------------
|
|
int32_t mddp_drv_attach(
|
|
struct mddp_drv_conf_t *conf,
|
|
struct mddp_drv_handle_t *handle)
|
|
{
|
|
if (MDDP_CHECK_APP_TYPE(conf->app_type) && handle)
|
|
return mddp_sm_reg_callback(conf, handle);
|
|
|
|
MDDP_C_LOG(MDDP_LL_WARN,
|
|
"%s: Failed to drv_attach, type(%d), handle(%p)!\n",
|
|
__func__, conf->app_type, handle);
|
|
|
|
return -EINVAL;
|
|
}
|
|
EXPORT_SYMBOL(mddp_drv_attach);
|
|
|
|
void mddp_drv_detach(
|
|
struct mddp_drv_conf_t *conf,
|
|
struct mddp_drv_handle_t *handle)
|
|
{
|
|
if (MDDP_CHECK_APP_TYPE(conf->app_type))
|
|
mddp_sm_dereg_callback(conf, handle);
|
|
}
|
|
EXPORT_SYMBOL(mddp_drv_detach);
|
|
|
|
int32_t mddp_on_enable(enum mddp_app_type_e in_type)
|
|
{
|
|
struct mddp_app_t *app;
|
|
uint32_t type;
|
|
uint8_t idx;
|
|
|
|
if (in_type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* MDDP ENABLE command.
|
|
*/
|
|
for (idx = 0; idx < MDDP_MOD_CNT; idx++) {
|
|
type = mddp_sm_module_list_s[idx];
|
|
app = mddp_get_app_inst(type);
|
|
mddp_sm_wait_pre(app);
|
|
mddp_sm_on_event(app, MDDP_EVT_FUNC_ENABLE);
|
|
mddp_sm_wait(app, MDDP_EVT_FUNC_ENABLE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t mddp_on_disable(enum mddp_app_type_e in_type)
|
|
{
|
|
struct mddp_app_t *app;
|
|
uint32_t type;
|
|
uint8_t idx;
|
|
|
|
if (in_type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* MDDP DISABLE command.
|
|
*/
|
|
for (idx = 0; idx < MDDP_MOD_CNT; idx++) {
|
|
type = mddp_sm_module_list_s[idx];
|
|
app = mddp_get_app_inst(type);
|
|
mddp_sm_wait_pre(app);
|
|
mddp_sm_on_event(app, MDDP_EVT_FUNC_DISABLE);
|
|
mddp_sm_wait(app, MDDP_EVT_FUNC_DISABLE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t mddp_on_activate(enum mddp_app_type_e type,
|
|
uint8_t *ul_dev_name, uint8_t *dl_dev_name)
|
|
{
|
|
struct mddp_app_t *app;
|
|
|
|
// NG. app_type is unknown!
|
|
if (!MDDP_CHECK_APP_TYPE(type))
|
|
return -EINVAL;
|
|
|
|
// NG. app is not configured!
|
|
app = mddp_get_app_inst(type);
|
|
if (!app->is_config)
|
|
return -EINVAL;
|
|
|
|
if (!mddp_f_dev_add_wan_dev(ul_dev_name))
|
|
return -EINVAL;
|
|
if (!mddp_f_dev_add_lan_dev(dl_dev_name, MDDP_WIFI_NETIF_ID)) {
|
|
mddp_f_dev_del_wan_dev(ul_dev_name);
|
|
return -EINVAL;
|
|
}
|
|
mddp_netdev_notifier_init();
|
|
|
|
/*
|
|
* MDDP ACTIVATE command.
|
|
*/
|
|
strlcpy(app->ap_cfg.ul_dev_name, ul_dev_name,
|
|
sizeof(app->ap_cfg.ul_dev_name));
|
|
strlcpy(app->ap_cfg.dl_dev_name, dl_dev_name,
|
|
sizeof(app->ap_cfg.dl_dev_name));
|
|
MDDP_C_LOG(MDDP_LL_INFO,
|
|
"%s: type(%d), app(%p), ul(%s), dl(%s).\n",
|
|
__func__, type, app,
|
|
app->ap_cfg.ul_dev_name, app->ap_cfg.dl_dev_name);
|
|
|
|
mddp_sm_wait_pre(app);
|
|
mddp_sm_on_event(app, MDDP_EVT_FUNC_ACT);
|
|
mddp_sm_wait(app, MDDP_EVT_FUNC_ACT);
|
|
mddp_u_set_wan_iface(ul_dev_name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t mddp_on_deactivate(enum mddp_app_type_e type)
|
|
{
|
|
struct mddp_app_t *app;
|
|
|
|
// NG. app_type is unknown!
|
|
if (!MDDP_CHECK_APP_TYPE(type))
|
|
return -EINVAL;
|
|
|
|
// NG. app is not configured!
|
|
app = mddp_get_app_inst(type);
|
|
if (!app->is_config)
|
|
return -EINVAL;
|
|
|
|
mddp_netdev_notifier_exit();
|
|
/*
|
|
* MDDP DEACTIVATE command.
|
|
*/
|
|
mddp_sm_wait_pre(app);
|
|
mddp_sm_on_event(app, MDDP_EVT_FUNC_DEACT);
|
|
mddp_sm_wait(app, MDDP_EVT_FUNC_DEACT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t mddp_on_get_offload_stats(
|
|
enum mddp_app_type_e type,
|
|
uint8_t *buf,
|
|
uint32_t *buf_len)
|
|
{
|
|
if (type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* MDDP GET_OFFLOAD_STATISTICS command.
|
|
*/
|
|
mddp_u_get_data_stats(buf, buf_len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t mddp_on_set_data_limit(
|
|
enum mddp_app_type_e type,
|
|
uint8_t *buf,
|
|
uint32_t buf_len)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
ret = mddp_u_set_data_limit(buf, buf_len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t mddp_on_set_warning_and_data_limit(
|
|
enum mddp_app_type_e type,
|
|
uint8_t *buf,
|
|
uint32_t buf_len)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
ret = mddp_u_set_warning_and_data_limit(buf, buf_len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t mddp_on_set_ct_value(
|
|
enum mddp_app_type_e type,
|
|
uint8_t *buf,
|
|
uint32_t buf_len)
|
|
{
|
|
int32_t ret;
|
|
|
|
if (type != MDDP_APP_TYPE_ALL)
|
|
return -EINVAL;
|
|
|
|
/*
|
|
* MDDP GET_OFFLOAD_STATISTICS command.
|
|
*/
|
|
ret = mddp_f_set_ct_value(buf, buf_len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Kernel functions.
|
|
//------------------------------------------------------------------------------
|
|
static int mddp_init_steps;
|
|
static void mddp_exit(void)
|
|
{
|
|
synchronize_net();
|
|
|
|
switch (mddp_init_steps) {
|
|
case 4:
|
|
mddp_filter_uninit();
|
|
/* fallthrough */
|
|
case 3:
|
|
mddp_dev_uninit();
|
|
/* fallthrough */
|
|
case 2:
|
|
mddp_ipc_uninit();
|
|
/* fallthrough */
|
|
case 1:
|
|
mddp_sm_uninit();
|
|
/* fallthrough */
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int __init mddp_init(void)
|
|
{
|
|
int32_t ret = 0;
|
|
|
|
ret = mddp_sm_init();
|
|
if (ret < 0)
|
|
goto _init_fail;
|
|
|
|
mddp_init_steps++;
|
|
ret = mddp_ipc_init();
|
|
if (ret < 0)
|
|
goto _init_fail;
|
|
|
|
mddp_init_steps++;
|
|
ret = mddp_dev_init();
|
|
if (ret < 0)
|
|
goto _init_fail;
|
|
|
|
mddp_init_steps++;
|
|
ret = mddp_filter_init();
|
|
if (ret < 0)
|
|
goto _init_fail;
|
|
|
|
mddp_init_steps++;
|
|
return 0;
|
|
|
|
_init_fail:
|
|
mddp_exit();
|
|
return 0;
|
|
}
|
|
module_init(mddp_init);
|
|
module_exit(mddp_exit);
|
|
|
|
MODULE_LICENSE("GPL v2");
|