162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * access_tokenid.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define pr_fmt(fmt) "access_token_id: " fmt
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/fs.h>
1362306a36Sopenharmony_ci#include <linux/miscdevice.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/rwlock.h>
1662306a36Sopenharmony_ci#include <linux/sched.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include "access_tokenid.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciDEFINE_RWLOCK(token_rwlock);
2162306a36Sopenharmony_ci#define ACCESS_TOKEN_UID KUIDT_INIT(3020)
2262306a36Sopenharmony_ci#define MAX_NODE_NUM 500
2362306a36Sopenharmony_ci#define UINT32_T_BITS 32
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct kmem_cache *g_cache = NULL;
2662306a36Sopenharmony_cistatic struct token_perm_node *g_token_perm_root = NULL;
2762306a36Sopenharmony_cistatic size_t g_total_node_num = 0;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciint access_tokenid_get_tokenid(struct file *file, void __user *uarg)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	return copy_to_user(uarg, &current->token,
3262306a36Sopenharmony_ci			    sizeof(current->token)) ? -EFAULT : 0;
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic bool check_permission_for_set_tokenid(struct file *file, unsigned long long tokenid)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	kuid_t uid = current_uid();
3862306a36Sopenharmony_ci	struct inode *inode = file->f_inode;
3962306a36Sopenharmony_ci	access_tokenid_inner *tokenid_inner = (access_tokenid_inner *)&tokenid;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (inode == NULL) {
4262306a36Sopenharmony_ci		pr_err("%s: file inode is null\n", __func__);
4362306a36Sopenharmony_ci		return false;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (uid_eq(uid, GLOBAL_ROOT_UID) ||
4762306a36Sopenharmony_ci	    uid_eq(uid, inode->i_uid)) {
4862306a36Sopenharmony_ci		return true;
4962306a36Sopenharmony_ci	} else if (uid_eq(uid, NWEBSPAWN_UID) && (tokenid_inner->render_flag == 1)) {
5062306a36Sopenharmony_ci		return true;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	return false;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciint access_tokenid_set_tokenid(struct file *file, void __user *uarg)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	unsigned long long tmp = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
6162306a36Sopenharmony_ci		return -EFAULT;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (!check_permission_for_set_tokenid(file, tmp))
6462306a36Sopenharmony_ci		return -EPERM;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	current->token = tmp;
6762306a36Sopenharmony_ci	return 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic bool check_permission_for_ftokenid(struct file *file)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	int i;
7362306a36Sopenharmony_ci	struct group_info *group_info;
7462306a36Sopenharmony_ci	kuid_t uid = current_uid();
7562306a36Sopenharmony_ci	struct inode *inode = file->f_inode;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (inode == NULL) {
7862306a36Sopenharmony_ci		pr_err("%s: file inode is null\n", __func__);
7962306a36Sopenharmony_ci		return false;
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (uid_eq(uid, GLOBAL_ROOT_UID))
8362306a36Sopenharmony_ci		return true;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	group_info = get_current_groups();
8662306a36Sopenharmony_ci	for (i = 0; i < group_info->ngroups; i++) {
8762306a36Sopenharmony_ci		kgid_t gid = group_info->gid[i];
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		if (gid_eq(gid, inode->i_gid)) {
9062306a36Sopenharmony_ci			put_group_info(group_info);
9162306a36Sopenharmony_ci			return true;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci	}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	put_group_info(group_info);
9662306a36Sopenharmony_ci	return false;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint access_tokenid_get_ftokenid(struct file *file, void __user *uarg)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	if (!check_permission_for_ftokenid(file))
10262306a36Sopenharmony_ci		return -EPERM;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return copy_to_user(uarg, &current->ftoken,
10562306a36Sopenharmony_ci			    sizeof(current->ftoken)) ? -EFAULT : 0;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint access_tokenid_set_ftokenid(struct file *file, void __user *uarg)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	unsigned long long tmp = 0;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (!check_permission_for_ftokenid(file))
11362306a36Sopenharmony_ci		return -EPERM;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
11662306a36Sopenharmony_ci		return -EFAULT;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	current->ftoken = tmp;
11962306a36Sopenharmony_ci	return 0;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic bool check_permission_for_set_token_permission(void)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	kuid_t uid = current_uid();
12562306a36Sopenharmony_ci	return uid_eq(uid, ACCESS_TOKEN_UID);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic void add_node_to_left_tree_tail(struct token_perm_node *root_node, struct token_perm_node *node)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	if ((root_node == NULL) || (node == NULL))
13162306a36Sopenharmony_ci		return;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	struct token_perm_node *current_node = root_node;
13462306a36Sopenharmony_ci	while (true) {
13562306a36Sopenharmony_ci		if (current_node->left == NULL) {
13662306a36Sopenharmony_ci			current_node->left = node;
13762306a36Sopenharmony_ci			break;
13862306a36Sopenharmony_ci		}
13962306a36Sopenharmony_ci		current_node = current_node->left;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void find_node_by_token(struct token_perm_node *root_node, uint32_t token,
14462306a36Sopenharmony_ci	struct token_perm_node **target_node, struct token_perm_node **parent_node)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	*target_node = NULL;
14762306a36Sopenharmony_ci	*parent_node = NULL;
14862306a36Sopenharmony_ci	struct token_perm_node *current_node = root_node;
14962306a36Sopenharmony_ci	while (current_node != NULL) {
15062306a36Sopenharmony_ci		if (current_node->perm_data.token == token) {
15162306a36Sopenharmony_ci			*target_node = current_node;
15262306a36Sopenharmony_ci			break;
15362306a36Sopenharmony_ci		}
15462306a36Sopenharmony_ci		*parent_node = current_node;
15562306a36Sopenharmony_ci		if (current_node->perm_data.token > token) {
15662306a36Sopenharmony_ci			current_node = current_node->left;
15762306a36Sopenharmony_ci		} else {
15862306a36Sopenharmony_ci			current_node = current_node->right;
15962306a36Sopenharmony_ci		}
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int add_node_to_tree(struct token_perm_node *root_node, struct token_perm_node *node)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct token_perm_node *target_node = NULL;
16662306a36Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
16762306a36Sopenharmony_ci	find_node_by_token(root_node, node->perm_data.token, &target_node, &parent_node);
16862306a36Sopenharmony_ci	if (target_node != NULL) {
16962306a36Sopenharmony_ci		target_node->perm_data = node->perm_data;
17062306a36Sopenharmony_ci		return 0;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	if (g_total_node_num >= MAX_NODE_NUM) {
17362306a36Sopenharmony_ci		pr_err("%s: the number of token nodes is exceeded.\n", __func__);
17462306a36Sopenharmony_ci		return -EDQUOT;
17562306a36Sopenharmony_ci	}
17662306a36Sopenharmony_ci	if (parent_node == NULL) {
17762306a36Sopenharmony_ci		g_token_perm_root = node;
17862306a36Sopenharmony_ci	} else if (parent_node->perm_data.token > node->perm_data.token) {
17962306a36Sopenharmony_ci		parent_node->left = node;
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		parent_node->right = node;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	g_total_node_num++;
18462306a36Sopenharmony_ci	return 1;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic struct token_perm_node *remove_node_by_token(struct token_perm_node *root_node, uint32_t token)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct token_perm_node *target_node = NULL;
19062306a36Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
19162306a36Sopenharmony_ci	find_node_by_token(root_node, token, &target_node, &parent_node);
19262306a36Sopenharmony_ci	if (target_node == NULL) {
19362306a36Sopenharmony_ci		pr_err("%s: target token to be removed not found.\n", __func__);
19462306a36Sopenharmony_ci		return NULL;
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	struct token_perm_node **new_node_addr = NULL;
19862306a36Sopenharmony_ci	if (parent_node == NULL) {
19962306a36Sopenharmony_ci		new_node_addr = &root_node;
20062306a36Sopenharmony_ci	} else if (parent_node->perm_data.token > token) {
20162306a36Sopenharmony_ci		new_node_addr = &(parent_node->left);
20262306a36Sopenharmony_ci	} else {
20362306a36Sopenharmony_ci		new_node_addr = &(parent_node->right);
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci	if (target_node->right != NULL) {
20662306a36Sopenharmony_ci		*new_node_addr = target_node->right;
20762306a36Sopenharmony_ci		add_node_to_left_tree_tail(target_node->right, target_node->left);
20862306a36Sopenharmony_ci	} else {
20962306a36Sopenharmony_ci		*new_node_addr = target_node->left;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci	g_total_node_num--;
21262306a36Sopenharmony_ci	return target_node;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ciint access_tokenid_add_permission(struct file *file, void __user *uarg)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	if (!check_permission_for_set_token_permission())
21862306a36Sopenharmony_ci		return -EPERM;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	struct token_perm_node *node = kmem_cache_zalloc(g_cache, GFP_KERNEL);
22162306a36Sopenharmony_ci	if (node == NULL)
22262306a36Sopenharmony_ci		return -ENOMEM;
22362306a36Sopenharmony_ci	if (copy_from_user(&(node->perm_data), uarg, sizeof(ioctl_add_perm_data))) {
22462306a36Sopenharmony_ci		kmem_cache_free(g_cache, node);
22562306a36Sopenharmony_ci		return -EFAULT;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	write_lock(&token_rwlock);
22962306a36Sopenharmony_ci	int ret = add_node_to_tree(g_token_perm_root, node);
23062306a36Sopenharmony_ci	write_unlock(&token_rwlock);
23162306a36Sopenharmony_ci	if (ret <= 0) {
23262306a36Sopenharmony_ci		kmem_cache_free(g_cache, node);
23362306a36Sopenharmony_ci		return ret;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	return 0;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciint access_tokenid_remove_permission(struct file *file, void __user *uarg)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	if (!check_permission_for_set_token_permission())
24162306a36Sopenharmony_ci		return -EPERM;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	uint32_t token = 0;
24462306a36Sopenharmony_ci	if (copy_from_user(&token, uarg, sizeof(token)))
24562306a36Sopenharmony_ci		return -EFAULT;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	write_lock(&token_rwlock);
24862306a36Sopenharmony_ci	struct token_perm_node *target_node = remove_node_by_token(g_token_perm_root, token);
24962306a36Sopenharmony_ci	write_unlock(&token_rwlock);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (target_node != NULL)
25262306a36Sopenharmony_ci		kmem_cache_free(g_cache, target_node);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ciint access_tokenid_set_permission(struct file *file, void __user *uarg)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	if (!check_permission_for_set_token_permission())
26062306a36Sopenharmony_ci		return -EPERM;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ioctl_set_get_perm_data set_perm_data;
26362306a36Sopenharmony_ci	if (copy_from_user(&set_perm_data, uarg, sizeof(set_perm_data)))
26462306a36Sopenharmony_ci		return -EFAULT;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	uint32_t idx = set_perm_data.op_code / UINT32_T_BITS;
26762306a36Sopenharmony_ci	if (idx >= MAX_PERM_GROUP_NUM) {
26862306a36Sopenharmony_ci		pr_err("%s: invalid op_code.\n", __func__);
26962306a36Sopenharmony_ci		return -EINVAL;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	struct token_perm_node *target_node = NULL;
27362306a36Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
27462306a36Sopenharmony_ci	write_lock(&token_rwlock);
27562306a36Sopenharmony_ci	find_node_by_token(g_token_perm_root, set_perm_data.token, &target_node, &parent_node);
27662306a36Sopenharmony_ci	if (target_node == NULL) {
27762306a36Sopenharmony_ci		write_unlock(&token_rwlock);
27862306a36Sopenharmony_ci		pr_err("%s: token not found.\n", __func__);
27962306a36Sopenharmony_ci		return -ENODATA;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	uint32_t bit_idx = set_perm_data.op_code % UINT32_T_BITS;
28262306a36Sopenharmony_ci	if (set_perm_data.is_granted) {
28362306a36Sopenharmony_ci		target_node->perm_data.perm[idx] |= (uint32_t)0x01 << bit_idx;
28462306a36Sopenharmony_ci	} else {
28562306a36Sopenharmony_ci		target_node->perm_data.perm[idx] &= ~((uint32_t)0x01 << bit_idx);
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci	write_unlock(&token_rwlock);
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint access_tokenid_get_permission(struct file *file, void __user *uarg)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	ioctl_set_get_perm_data get_perm_data;
29462306a36Sopenharmony_ci	if (copy_from_user(&get_perm_data, uarg, sizeof(get_perm_data)))
29562306a36Sopenharmony_ci		return -EFAULT;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	uint32_t idx = get_perm_data.op_code / UINT32_T_BITS;
29862306a36Sopenharmony_ci	if (idx >= MAX_PERM_GROUP_NUM) {
29962306a36Sopenharmony_ci		pr_err("%s: invalid op_code.\n", __func__);
30062306a36Sopenharmony_ci		return -EINVAL;
30162306a36Sopenharmony_ci	}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	struct token_perm_node *target_node = NULL;
30462306a36Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
30562306a36Sopenharmony_ci	read_lock(&token_rwlock);
30662306a36Sopenharmony_ci	find_node_by_token(g_token_perm_root, get_perm_data.token, &target_node, &parent_node);
30762306a36Sopenharmony_ci	read_unlock(&token_rwlock);
30862306a36Sopenharmony_ci	if (target_node == NULL)
30962306a36Sopenharmony_ci		return -ENODATA;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	uint32_t bit_idx = get_perm_data.op_code % UINT32_T_BITS;
31262306a36Sopenharmony_ci	return (target_node->perm_data.perm[idx] & ((uint32_t)0x01 << bit_idx)) >> bit_idx;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_citypedef int (*access_token_id_func)(struct file *file, void __user *arg);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = {
31862306a36Sopenharmony_ci	NULL, /* reserved */
31962306a36Sopenharmony_ci	access_tokenid_get_tokenid,
32062306a36Sopenharmony_ci	access_tokenid_set_tokenid,
32162306a36Sopenharmony_ci	access_tokenid_get_ftokenid,
32262306a36Sopenharmony_ci	access_tokenid_set_ftokenid,
32362306a36Sopenharmony_ci	access_tokenid_add_permission,
32462306a36Sopenharmony_ci	access_tokenid_remove_permission,
32562306a36Sopenharmony_ci	access_tokenid_get_permission,
32662306a36Sopenharmony_ci	access_tokenid_set_permission,
32762306a36Sopenharmony_ci};
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic long access_tokenid_ioctl(struct file *file, unsigned int cmd,
33062306a36Sopenharmony_ci				 unsigned long arg)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	void __user *uarg = (void __user *)arg;
33362306a36Sopenharmony_ci	unsigned int func_cmd = _IOC_NR(cmd);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (uarg == NULL) {
33662306a36Sopenharmony_ci		pr_err("%s: invalid user uarg\n", __func__);
33762306a36Sopenharmony_ci		return -EINVAL;
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) {
34162306a36Sopenharmony_ci		pr_err("%s: access tokenid magic fail, TYPE=%d\n",
34262306a36Sopenharmony_ci		       __func__, _IOC_TYPE(cmd));
34362306a36Sopenharmony_ci		return -EINVAL;
34462306a36Sopenharmony_ci	}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (func_cmd >= ACCESS_TOKENID_MAX_NR) {
34762306a36Sopenharmony_ci		pr_err("%s: access tokenid cmd error, cmd:%d\n",
34862306a36Sopenharmony_ci			__func__, func_cmd);
34962306a36Sopenharmony_ci		return -EINVAL;
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (g_func_array[func_cmd])
35362306a36Sopenharmony_ci		return (*g_func_array[func_cmd])(file, uarg);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	return -EINVAL;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic const struct file_operations access_tokenid_fops = {
35962306a36Sopenharmony_ci	.owner		= THIS_MODULE,
36062306a36Sopenharmony_ci	.unlocked_ioctl	= access_tokenid_ioctl,
36162306a36Sopenharmony_ci	.compat_ioctl	= access_tokenid_ioctl,
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic struct miscdevice access_tokenid_device = {
36562306a36Sopenharmony_ci	.minor	= MISC_DYNAMIC_MINOR,
36662306a36Sopenharmony_ci	.name	= "access_token_id",
36762306a36Sopenharmony_ci	.fops	= &access_tokenid_fops,
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic int access_tokenid_init_module(void)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	int err;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	err = misc_register(&access_tokenid_device);
37562306a36Sopenharmony_ci	if (err < 0) {
37662306a36Sopenharmony_ci		pr_err("access_tokenid register failed\n");
37762306a36Sopenharmony_ci		return err;
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	g_cache = kmem_cache_create("access_token_node", sizeof(struct token_perm_node), 0, SLAB_HWCACHE_ALIGN, NULL);
38162306a36Sopenharmony_ci	if (g_cache == NULL) {
38262306a36Sopenharmony_ci		pr_err("access_tokenid kmem_cache create failed\n");
38362306a36Sopenharmony_ci		return -ENOMEM;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci	pr_info("access_tokenid init success\n");
38662306a36Sopenharmony_ci	return 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void access_tokenid_exit_module(void)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	kmem_cache_destroy(g_cache);
39262306a36Sopenharmony_ci	misc_deregister(&access_tokenid_device);
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci/* module entry points */
39662306a36Sopenharmony_cimodule_init(access_tokenid_init_module);
39762306a36Sopenharmony_cimodule_exit(access_tokenid_exit_module);
398