18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * access_tokenid.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "access_token_id: " fmt
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/errno.h>
128c2ecf20Sopenharmony_ci#include <linux/fs.h>
138c2ecf20Sopenharmony_ci#include <linux/miscdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/rwlock.h>
168c2ecf20Sopenharmony_ci#include <linux/sched.h>
178c2ecf20Sopenharmony_ci#include <linux/slab.h>
188c2ecf20Sopenharmony_ci#include "access_tokenid.h"
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ciDEFINE_RWLOCK(token_rwlock);
218c2ecf20Sopenharmony_ci#define ACCESS_TOKEN_UID KUIDT_INIT(3020)
228c2ecf20Sopenharmony_ci#define MAX_NODE_NUM 500
238c2ecf20Sopenharmony_ci#define UINT32_T_BITS 32
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic struct kmem_cache *g_cache = NULL;
268c2ecf20Sopenharmony_cistatic struct token_perm_node *g_token_perm_root = NULL;
278c2ecf20Sopenharmony_cistatic size_t g_total_node_num = 0;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ciint access_tokenid_get_tokenid(struct file *file, void __user *uarg)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	return copy_to_user(uarg, &current->token,
328c2ecf20Sopenharmony_ci			    sizeof(current->token)) ? -EFAULT : 0;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic bool check_permission_for_set_tokenid(struct file *file, unsigned long long tokenid)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	kuid_t uid = current_uid();
388c2ecf20Sopenharmony_ci	struct inode *inode = file->f_inode;
398c2ecf20Sopenharmony_ci	access_tokenid_inner *tokenid_inner = (access_tokenid_inner *)&tokenid;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (inode == NULL) {
428c2ecf20Sopenharmony_ci		pr_err("%s: file inode is null\n", __func__);
438c2ecf20Sopenharmony_ci		return false;
448c2ecf20Sopenharmony_ci	}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (uid_eq(uid, GLOBAL_ROOT_UID) ||
478c2ecf20Sopenharmony_ci	    uid_eq(uid, inode->i_uid)) {
488c2ecf20Sopenharmony_ci		return true;
498c2ecf20Sopenharmony_ci	} else if (uid_eq(uid, NWEBSPAWN_UID) && (tokenid_inner->render_flag == 1)) {
508c2ecf20Sopenharmony_ci		return true;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return false;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint access_tokenid_set_tokenid(struct file *file, void __user *uarg)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	unsigned long long tmp = 0;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
618c2ecf20Sopenharmony_ci		return -EFAULT;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (!check_permission_for_set_tokenid(file, tmp))
648c2ecf20Sopenharmony_ci		return -EPERM;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	current->token = tmp;
678c2ecf20Sopenharmony_ci	return 0;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic bool check_permission_for_ftokenid(struct file *file)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	int i;
738c2ecf20Sopenharmony_ci	struct group_info *group_info;
748c2ecf20Sopenharmony_ci	kuid_t uid = current_uid();
758c2ecf20Sopenharmony_ci	struct inode *inode = file->f_inode;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (inode == NULL) {
788c2ecf20Sopenharmony_ci		pr_err("%s: file inode is null\n", __func__);
798c2ecf20Sopenharmony_ci		return false;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (uid_eq(uid, GLOBAL_ROOT_UID))
838c2ecf20Sopenharmony_ci		return true;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	group_info = get_current_groups();
868c2ecf20Sopenharmony_ci	for (i = 0; i < group_info->ngroups; i++) {
878c2ecf20Sopenharmony_ci		kgid_t gid = group_info->gid[i];
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci		if (gid_eq(gid, inode->i_gid)) {
908c2ecf20Sopenharmony_ci			put_group_info(group_info);
918c2ecf20Sopenharmony_ci			return true;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	put_group_info(group_info);
968c2ecf20Sopenharmony_ci	return false;
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ciint access_tokenid_get_ftokenid(struct file *file, void __user *uarg)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	if (!check_permission_for_ftokenid(file))
1028c2ecf20Sopenharmony_ci		return -EPERM;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	return copy_to_user(uarg, &current->ftoken,
1058c2ecf20Sopenharmony_ci			    sizeof(current->ftoken)) ? -EFAULT : 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ciint access_tokenid_set_ftokenid(struct file *file, void __user *uarg)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	unsigned long long tmp = 0;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	if (!check_permission_for_ftokenid(file))
1138c2ecf20Sopenharmony_ci		return -EPERM;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
1168c2ecf20Sopenharmony_ci		return -EFAULT;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	current->ftoken = tmp;
1198c2ecf20Sopenharmony_ci	return 0;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic bool check_permission_for_set_token_permission()
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	kuid_t uid = current_uid();
1258c2ecf20Sopenharmony_ci	return uid_eq(uid, ACCESS_TOKEN_UID);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic void add_node_to_left_tree_tail(struct token_perm_node *root_node, struct token_perm_node *node)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	if ((root_node == NULL) || (node == NULL))
1318c2ecf20Sopenharmony_ci		return;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	struct token_perm_node *current_node = root_node;
1348c2ecf20Sopenharmony_ci	while (true) {
1358c2ecf20Sopenharmony_ci		if (current_node->left == NULL) {
1368c2ecf20Sopenharmony_ci			current_node->left = node;
1378c2ecf20Sopenharmony_ci			break;
1388c2ecf20Sopenharmony_ci		}
1398c2ecf20Sopenharmony_ci		current_node = current_node->left;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic void find_node_by_token(struct token_perm_node *root_node, uint32_t token,
1448c2ecf20Sopenharmony_ci	struct token_perm_node **target_node, struct token_perm_node **parent_node)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	*target_node = NULL;
1478c2ecf20Sopenharmony_ci	*parent_node = NULL;
1488c2ecf20Sopenharmony_ci	struct token_perm_node *current_node = root_node;
1498c2ecf20Sopenharmony_ci	while (current_node != NULL) {
1508c2ecf20Sopenharmony_ci		if (current_node->perm_data.token == token) {
1518c2ecf20Sopenharmony_ci			*target_node = current_node;
1528c2ecf20Sopenharmony_ci			break;
1538c2ecf20Sopenharmony_ci		}
1548c2ecf20Sopenharmony_ci		*parent_node = current_node;
1558c2ecf20Sopenharmony_ci		if (current_node->perm_data.token > token) {
1568c2ecf20Sopenharmony_ci			current_node = current_node->left;
1578c2ecf20Sopenharmony_ci		} else {
1588c2ecf20Sopenharmony_ci			current_node = current_node->right;
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic int add_node_to_tree(struct token_perm_node **root_node, struct token_perm_node *node)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	if (root_node == NULL) {
1668c2ecf20Sopenharmony_ci		pr_err("%s: invalid root_node.\n", __func__);
1678c2ecf20Sopenharmony_ci		return -EINVAL;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci	struct token_perm_node *target_node = NULL;
1708c2ecf20Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
1718c2ecf20Sopenharmony_ci	find_node_by_token(*root_node, node->perm_data.token, &target_node, &parent_node);
1728c2ecf20Sopenharmony_ci	if (target_node != NULL) {
1738c2ecf20Sopenharmony_ci		target_node->perm_data = node->perm_data;
1748c2ecf20Sopenharmony_ci		return 0;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci	if (g_total_node_num >= MAX_NODE_NUM) {
1778c2ecf20Sopenharmony_ci		pr_err("%s: the number of token nodes is exceeded.\n", __func__);
1788c2ecf20Sopenharmony_ci		return -EDQUOT;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	if (parent_node == NULL) {
1818c2ecf20Sopenharmony_ci		*root_node = node;
1828c2ecf20Sopenharmony_ci	} else if (parent_node->perm_data.token > node->perm_data.token) {
1838c2ecf20Sopenharmony_ci		parent_node->left = node;
1848c2ecf20Sopenharmony_ci	} else {
1858c2ecf20Sopenharmony_ci		parent_node->right = node;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci	g_total_node_num++;
1888c2ecf20Sopenharmony_ci	return 1;
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_cistatic struct token_perm_node *remove_node_by_token(struct token_perm_node **root_node, uint32_t token)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	if (root_node == NULL) {
1948c2ecf20Sopenharmony_ci		pr_err("%s: invalid root_node.\n", __func__);
1958c2ecf20Sopenharmony_ci		return NULL;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci	struct token_perm_node *target_node = NULL;
1988c2ecf20Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
1998c2ecf20Sopenharmony_ci	find_node_by_token(*root_node, token, &target_node, &parent_node);
2008c2ecf20Sopenharmony_ci	if (target_node == NULL) {
2018c2ecf20Sopenharmony_ci		pr_err("%s: target token to be removed not found.\n", __func__);
2028c2ecf20Sopenharmony_ci		return NULL;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	struct token_perm_node **new_node_addr = NULL;
2068c2ecf20Sopenharmony_ci	if (parent_node == NULL) {
2078c2ecf20Sopenharmony_ci		new_node_addr = root_node;
2088c2ecf20Sopenharmony_ci	} else if (parent_node->perm_data.token > token) {
2098c2ecf20Sopenharmony_ci		new_node_addr = &(parent_node->left);
2108c2ecf20Sopenharmony_ci	} else {
2118c2ecf20Sopenharmony_ci		new_node_addr = &(parent_node->right);
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	if (target_node->right != NULL) {
2148c2ecf20Sopenharmony_ci		*new_node_addr = target_node->right;
2158c2ecf20Sopenharmony_ci		add_node_to_left_tree_tail(target_node->right, target_node->left);
2168c2ecf20Sopenharmony_ci	} else {
2178c2ecf20Sopenharmony_ci		*new_node_addr = target_node->left;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci	g_total_node_num--;
2208c2ecf20Sopenharmony_ci	return target_node;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciint access_tokenid_add_permission(struct file *file, void __user *uarg)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	if (!check_permission_for_set_token_permission())
2268c2ecf20Sopenharmony_ci		return -EPERM;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	struct token_perm_node *node = kmem_cache_zalloc(g_cache, GFP_KERNEL);
2298c2ecf20Sopenharmony_ci	if (node == NULL)
2308c2ecf20Sopenharmony_ci		return -ENOMEM;
2318c2ecf20Sopenharmony_ci	if (copy_from_user(&(node->perm_data), uarg, sizeof(ioctl_add_perm_data))) {
2328c2ecf20Sopenharmony_ci		kmem_cache_free(g_cache, node);
2338c2ecf20Sopenharmony_ci		return -EFAULT;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	write_lock(&token_rwlock);
2378c2ecf20Sopenharmony_ci	int ret = add_node_to_tree(&g_token_perm_root, node);
2388c2ecf20Sopenharmony_ci	write_unlock(&token_rwlock);
2398c2ecf20Sopenharmony_ci	if (ret <= 0) {
2408c2ecf20Sopenharmony_ci		kmem_cache_free(g_cache, node);
2418c2ecf20Sopenharmony_ci		return ret;
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci	return 0;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciint access_tokenid_remove_permission(struct file *file, void __user *uarg)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	if (!check_permission_for_set_token_permission())
2498c2ecf20Sopenharmony_ci		return -EPERM;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	uint32_t token = 0;
2528c2ecf20Sopenharmony_ci	if (copy_from_user(&token, uarg, sizeof(token)))
2538c2ecf20Sopenharmony_ci		return -EFAULT;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	write_lock(&token_rwlock);
2568c2ecf20Sopenharmony_ci	struct token_perm_node *target_node = remove_node_by_token(&g_token_perm_root, token);
2578c2ecf20Sopenharmony_ci	if (target_node != NULL)
2588c2ecf20Sopenharmony_ci		kmem_cache_free(g_cache, target_node);
2598c2ecf20Sopenharmony_ci	write_unlock(&token_rwlock);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return 0;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint access_tokenid_set_permission(struct file *file, void __user *uarg)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	if (!check_permission_for_set_token_permission())
2678c2ecf20Sopenharmony_ci		return -EPERM;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	ioctl_set_get_perm_data set_perm_data;
2708c2ecf20Sopenharmony_ci	if (copy_from_user(&set_perm_data, uarg, sizeof(set_perm_data)))
2718c2ecf20Sopenharmony_ci		return -EFAULT;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	uint32_t idx = set_perm_data.op_code / UINT32_T_BITS;
2748c2ecf20Sopenharmony_ci	if (idx >= MAX_PERM_GROUP_NUM) {
2758c2ecf20Sopenharmony_ci		pr_err("%s: invalid op_code.\n", __func__);
2768c2ecf20Sopenharmony_ci		return -EINVAL;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	struct token_perm_node *target_node = NULL;
2808c2ecf20Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
2818c2ecf20Sopenharmony_ci	write_lock(&token_rwlock);
2828c2ecf20Sopenharmony_ci	find_node_by_token(g_token_perm_root, set_perm_data.token, &target_node, &parent_node);
2838c2ecf20Sopenharmony_ci	if (target_node == NULL) {
2848c2ecf20Sopenharmony_ci		write_unlock(&token_rwlock);
2858c2ecf20Sopenharmony_ci		pr_err("%s: token not found.\n", __func__);
2868c2ecf20Sopenharmony_ci		return -ENODATA;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	uint32_t bit_idx = set_perm_data.op_code % UINT32_T_BITS;
2898c2ecf20Sopenharmony_ci	if (set_perm_data.is_granted) {
2908c2ecf20Sopenharmony_ci		target_node->perm_data.perm[idx] |= (uint32_t)0x01 << bit_idx;
2918c2ecf20Sopenharmony_ci	} else {
2928c2ecf20Sopenharmony_ci		target_node->perm_data.perm[idx] &= ~((uint32_t)0x01 << bit_idx);
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	write_unlock(&token_rwlock);
2958c2ecf20Sopenharmony_ci	return 0;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ciint access_tokenid_get_permission(struct file *file, void __user *uarg)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	ioctl_set_get_perm_data get_perm_data;
3018c2ecf20Sopenharmony_ci	if (copy_from_user(&get_perm_data, uarg, sizeof(get_perm_data)))
3028c2ecf20Sopenharmony_ci		return -EFAULT;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	uint32_t idx = get_perm_data.op_code / UINT32_T_BITS;
3058c2ecf20Sopenharmony_ci	if (idx >= MAX_PERM_GROUP_NUM) {
3068c2ecf20Sopenharmony_ci		pr_err("%s: invalid op_code.\n", __func__);
3078c2ecf20Sopenharmony_ci		return -EINVAL;
3088c2ecf20Sopenharmony_ci	}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	struct token_perm_node *target_node = NULL;
3118c2ecf20Sopenharmony_ci	struct token_perm_node *parent_node = NULL;
3128c2ecf20Sopenharmony_ci	read_lock(&token_rwlock);
3138c2ecf20Sopenharmony_ci	find_node_by_token(g_token_perm_root, get_perm_data.token, &target_node, &parent_node);
3148c2ecf20Sopenharmony_ci	if (target_node == NULL) {
3158c2ecf20Sopenharmony_ci		read_unlock(&token_rwlock);
3168c2ecf20Sopenharmony_ci		return -ENODATA;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	uint32_t bit_idx = get_perm_data.op_code % UINT32_T_BITS;
3208c2ecf20Sopenharmony_ci	int ret = (target_node->perm_data.perm[idx] & ((uint32_t)0x01 << bit_idx)) >> bit_idx;
3218c2ecf20Sopenharmony_ci	read_unlock(&token_rwlock);
3228c2ecf20Sopenharmony_ci	return ret;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_citypedef int (*access_token_id_func)(struct file *file, void __user *arg);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = {
3288c2ecf20Sopenharmony_ci	NULL, /* reserved */
3298c2ecf20Sopenharmony_ci	access_tokenid_get_tokenid,
3308c2ecf20Sopenharmony_ci	access_tokenid_set_tokenid,
3318c2ecf20Sopenharmony_ci	access_tokenid_get_ftokenid,
3328c2ecf20Sopenharmony_ci	access_tokenid_set_ftokenid,
3338c2ecf20Sopenharmony_ci	access_tokenid_add_permission,
3348c2ecf20Sopenharmony_ci	access_tokenid_remove_permission,
3358c2ecf20Sopenharmony_ci	access_tokenid_get_permission,
3368c2ecf20Sopenharmony_ci	access_tokenid_set_permission,
3378c2ecf20Sopenharmony_ci};
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic long access_tokenid_ioctl(struct file *file, unsigned int cmd,
3408c2ecf20Sopenharmony_ci				 unsigned long arg)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	void __user *uarg = (void __user *)arg;
3438c2ecf20Sopenharmony_ci	unsigned int func_cmd = _IOC_NR(cmd);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (uarg == NULL) {
3468c2ecf20Sopenharmony_ci		pr_err("%s: invalid user uarg\n", __func__);
3478c2ecf20Sopenharmony_ci		return -EINVAL;
3488c2ecf20Sopenharmony_ci	}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) {
3518c2ecf20Sopenharmony_ci		pr_err("%s: access tokenid magic fail, TYPE=%d\n",
3528c2ecf20Sopenharmony_ci		       __func__, _IOC_TYPE(cmd));
3538c2ecf20Sopenharmony_ci		return -EINVAL;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	if (func_cmd >= ACCESS_TOKENID_MAX_NR) {
3578c2ecf20Sopenharmony_ci		pr_err("%s: access tokenid cmd error, cmd:%d\n",
3588c2ecf20Sopenharmony_ci			__func__, func_cmd);
3598c2ecf20Sopenharmony_ci		return -EINVAL;
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	if (g_func_array[func_cmd])
3638c2ecf20Sopenharmony_ci		return (*g_func_array[func_cmd])(file, uarg);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	return -EINVAL;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_cistatic const struct file_operations access_tokenid_fops = {
3698c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
3708c2ecf20Sopenharmony_ci	.unlocked_ioctl	= access_tokenid_ioctl,
3718c2ecf20Sopenharmony_ci	.compat_ioctl	= access_tokenid_ioctl,
3728c2ecf20Sopenharmony_ci};
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic struct miscdevice access_tokenid_device = {
3758c2ecf20Sopenharmony_ci	.minor	= MISC_DYNAMIC_MINOR,
3768c2ecf20Sopenharmony_ci	.name	= "access_token_id",
3778c2ecf20Sopenharmony_ci	.fops	= &access_tokenid_fops,
3788c2ecf20Sopenharmony_ci};
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic int access_tokenid_init_module(void)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	int err;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	err = misc_register(&access_tokenid_device);
3858c2ecf20Sopenharmony_ci	if (err < 0) {
3868c2ecf20Sopenharmony_ci		pr_err("access_tokenid register failed\n");
3878c2ecf20Sopenharmony_ci		return err;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	g_cache = kmem_cache_create("access_token_node", sizeof(struct token_perm_node), 0, SLAB_HWCACHE_ALIGN, NULL);
3918c2ecf20Sopenharmony_ci	if (g_cache == NULL) {
3928c2ecf20Sopenharmony_ci		pr_err("access_tokenid kmem_cache create failed\n");
3938c2ecf20Sopenharmony_ci		return -ENOMEM;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci	pr_info("access_tokenid init success\n");
3968c2ecf20Sopenharmony_ci	return 0;
3978c2ecf20Sopenharmony_ci}
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cistatic void access_tokenid_exit_module(void)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	kmem_cache_destroy(g_cache);
4028c2ecf20Sopenharmony_ci	misc_deregister(&access_tokenid_device);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci/* module entry points */
4068c2ecf20Sopenharmony_cimodule_init(access_tokenid_init_module);
4078c2ecf20Sopenharmony_cimodule_exit(access_tokenid_exit_module);
408