1
2#include <linux/init.h>
3#include <linux/module.h>
4#include <net/tcp.h>
5#include <linux/netfilter.h>
6#include <net/netfilter/nf_conntrack.h>
7#include <linux/skbuff.h>
8#include <net/ip.h>
9#include <linux/types.h>
10#include <net/sock.h>
11#include <linux/etherdevice.h>
12#include <linux/cdev.h>
13#include <linux/vmalloc.h>
14#include <linux/device.h>
15#include "cJSON.h"
16#include "app_filter.h"
17#include "af_utils.h"
18#include "af_log.h"
19#define AF_MAX_APP_TYPE_NUM 16
20#define AF_MAX_APP_NUM 256
21#define AF_DEV_NAME "appfilter"
22
23DEFINE_RWLOCK(af_rule_lock);
24
25#define af_rule_read_lock() read_lock_bh(&af_rule_lock);
26#define af_rule_read_unlock() read_unlock_bh(&af_rule_lock);
27#define af_rule_write_lock() write_lock_bh(&af_rule_lock);
28#define af_rule_write_unlock() write_unlock_bh(&af_rule_lock);
29
30static struct mutex af_cdev_mutex;
31struct af_config_dev
32{
33	dev_t id;
34	struct cdev char_dev;
35	struct class *c;
36};
37struct af_config_dev g_af_dev;
38
39struct af_cdev_file
40{
41	size_t size;
42	char buf[256 << 10];
43};
44
45enum AF_CONFIG_CMD
46{
47	AF_CMD_ADD_APPID = 1,
48	AF_CMD_DEL_APPID,
49	AF_CMD_CLEAN_APPID,
50	AF_CMD_SET_MAC_LIST,
51};
52
53char g_app_id_array[AF_MAX_APP_TYPE_NUM][AF_MAX_APP_NUM] = {0};
54
55void af_show_app_status(void)
56{
57	int i, j;
58	AF_DEBUG("#########show app status##########\n");
59	for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++)
60	{
61		for (j = 0; j < AF_MAX_APP_NUM; j++)
62		{
63
64			af_rule_read_lock();
65			if (g_app_id_array[i][j] == AF_TRUE)
66			{
67				AF_DEBUG("%d, %d\n", i, j);
68			}
69			af_rule_read_unlock();
70		}
71	}
72
73	AF_DEBUG("\n\n\n");
74}
75
76int af_change_app_status(cJSON *data_obj, int status)
77{
78	int i;
79	int id;
80	int type;
81	cJSON *appid_arr = NULL;
82	if (!data_obj)
83	{
84		AF_ERROR("data obj is null\n");
85		return -1;
86	}
87	appid_arr = cJSON_GetObjectItem(data_obj, "apps");
88	if (!appid_arr)
89	{
90		AF_ERROR("apps obj is null\n");
91		return -1;
92	}
93	for (i = 0; i < cJSON_GetArraySize(appid_arr); i++)
94	{
95		cJSON *appid_obj = cJSON_GetArrayItem(appid_arr, i);
96		if (!appid_obj)
97			return -1;
98		id = AF_APP_ID(appid_obj->valueint);
99		type = AF_APP_TYPE(appid_obj->valueint);
100		af_rule_write_lock();
101		g_app_id_array[type][id] = status;
102		af_rule_write_unlock();
103	}
104
105	return 0;
106}
107DEFINE_RWLOCK(af_mac_lock);
108#define MAX_AF_MAC_HASH_SIZE 64
109#define AF_MAC_LOCK_R() read_lock_bh(&af_mac_lock);
110#define AF_MAC_UNLOCK_R() read_unlock_bh(&af_mac_lock);
111#define AF_MAC_LOCK_W() write_lock_bh(&af_mac_lock);
112#define AF_MAC_UNLOCK_W() write_unlock_bh(&af_mac_lock);
113
114u32 total_mac = 0;
115struct list_head af_mac_list_table[MAX_AF_MAC_HASH_SIZE];
116
117void af_mac_list_init(void)
118{
119	int i;
120	AF_MAC_LOCK_W();
121	for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
122	{
123		INIT_LIST_HEAD(&af_mac_list_table[i]);
124	}
125	AF_MAC_UNLOCK_W();
126	AF_INFO("client list init......ok\n");
127}
128
129void af_mac_list_clear(void)
130{
131	int i;
132	af_mac_info_t *p = NULL;
133	char mac_str[32] = {0};
134
135	AF_DEBUG("clean list\n");
136	AF_MAC_LOCK_W();
137	for (i = 0; i < MAX_AF_MAC_HASH_SIZE; i++)
138	{
139		while (!list_empty(&af_mac_list_table[i]))
140		{
141			p = list_first_entry(&af_mac_list_table[i], af_mac_info_t, hlist);
142			memset(mac_str, 0x0, sizeof(mac_str));
143			sprintf(mac_str, MAC_FMT, MAC_ARRAY(p->mac));
144			AF_DEBUG("clean mac:%s\n", mac_str);
145			list_del(&(p->hlist));
146			kfree(p);
147		}
148	}
149	total_mac = 0;
150	AF_MAC_UNLOCK_W();
151}
152
153int hash_mac(unsigned char *mac)
154{
155	if (!mac)
156		return 0;
157	else
158		return mac[5] & (MAX_AF_MAC_HASH_SIZE - 1);
159}
160
161af_mac_info_t *find_af_mac(unsigned char *mac)
162{
163	af_mac_info_t *node;
164	unsigned int index;
165
166	index = hash_mac(mac);
167	list_for_each_entry(node, &af_mac_list_table[index], hlist)
168	{
169		if (0 == memcmp(node->mac, mac, 6))
170		{
171			AF_DEBUG("match mac:" MAC_FMT "\n", MAC_ARRAY(node->mac));
172			return node;
173		}
174	}
175	return NULL;
176}
177
178static af_mac_info_t *
179af_mac_add(unsigned char *mac)
180{
181	af_mac_info_t *node;
182	int index = 0;
183
184	node = (af_mac_info_t *)kmalloc(sizeof(af_mac_info_t), GFP_ATOMIC);
185	if (node == NULL)
186	{
187		AF_ERROR("kmalloc failed\n");
188		return NULL;
189	}
190
191	memset(node, 0, sizeof(af_mac_info_t));
192	memcpy(node->mac, mac, MAC_ADDR_LEN);
193
194	index = hash_mac(mac);
195
196	AF_LMT_INFO("new client mac=" MAC_FMT "\n", MAC_ARRAY(node->mac));
197	total_mac++;
198	list_add(&(node->hlist), &af_mac_list_table[index]);
199	return node;
200}
201
202int is_user_match_enable(void)
203{
204	return total_mac > 0;
205}
206int mac_to_hex(u8 *mac, u8 *mac_hex)
207{
208	u32 mac_tmp[MAC_ADDR_LEN];
209	int ret = 0, i = 0;
210	ret = sscanf(mac, "%02x:%02x:%02x:%02x:%02x:%02x",
211				 (unsigned int *)&mac_tmp[0],
212				 (unsigned int *)&mac_tmp[1],
213				 (unsigned int *)&mac_tmp[2],
214				 (unsigned int *)&mac_tmp[3],
215				 (unsigned int *)&mac_tmp[4],
216				 (unsigned int *)&mac_tmp[5]);
217	if (MAC_ADDR_LEN != ret)
218		return -1;
219	for (i = 0; i < MAC_ADDR_LEN; i++)
220	{
221		mac_hex[i] = mac_tmp[i];
222	}
223	return 0;
224}
225int af_set_mac_list(cJSON *data_obj)
226{
227	int i;
228	cJSON *mac_arr = NULL;
229	u8 mac_hex[MAC_ADDR_LEN] = {0};
230	if (!data_obj)
231	{
232		AF_ERROR("data obj is null\n");
233		return -1;
234	}
235	mac_arr = cJSON_GetObjectItem(data_obj, "mac_list");
236	if (!mac_arr)
237	{
238		AF_ERROR("apps obj is null\n");
239		return -1;
240	}
241	af_mac_list_clear();
242	for (i = 0; i < cJSON_GetArraySize(mac_arr); i++)
243	{
244		cJSON *mac_obj = cJSON_GetArrayItem(mac_arr, i);
245		if (!mac_obj)
246		{
247			AF_ERROR("appid obj is null\n");
248			return -1;
249		}
250		if (-1 == mac_to_hex(mac_obj->valuestring, mac_hex))
251		{
252			continue;
253		}
254		af_mac_add(mac_hex);
255	}
256	AF_DEBUG("## mac num = %d\n", total_mac);
257	return 0;
258}
259
260void af_init_app_status(void)
261{
262	int i, j;
263
264	for (i = 0; i < AF_MAX_APP_TYPE_NUM; i++)
265	{
266		for (j = 0; j < AF_MAX_APP_NUM; j++)
267		{
268			af_rule_write_lock();
269			g_app_id_array[i][j] = AF_FALSE;
270			af_rule_write_unlock();
271		}
272	}
273}
274int af_get_app_status(int appid)
275{
276	int status = 0;
277	int id = AF_APP_ID(appid);
278	int type = AF_APP_TYPE(appid);
279	af_rule_read_lock();
280	status = g_app_id_array[type][id];
281	af_rule_read_unlock();
282	return status;
283}
284/*
285add:
286{
287	"op":1,
288	"data"{
289		"apps":[]
290	}
291}
292clean
293{
294	"op":3,
295}
296
297*/
298int af_config_handle(char *config, unsigned int len)
299{
300	cJSON *config_obj = NULL;
301	cJSON *cmd_obj = NULL;
302	cJSON *data_obj = NULL;
303	if (!config || len == 0)
304	{
305		AF_ERROR("config or len is invalid\n");
306		return -1;
307	}
308	config_obj = cJSON_Parse(config);
309	if (!config_obj)
310	{
311		AF_ERROR("config_obj is NULL\n");
312		return -1;
313	}
314	cmd_obj = cJSON_GetObjectItem(config_obj, "op");
315	if (!cmd_obj)
316	{
317		AF_ERROR("not find op object\n");
318		return -1;
319	}
320	data_obj = cJSON_GetObjectItem(config_obj, "data");
321
322	switch (cmd_obj->valueint)
323	{
324	case AF_CMD_ADD_APPID:
325		if (!data_obj)
326			break;
327		af_change_app_status(data_obj, AF_TRUE);
328		break;
329	case AF_CMD_DEL_APPID:
330		if (!data_obj)
331			break;
332		af_change_app_status(data_obj, AF_FALSE);
333		break;
334	case AF_CMD_CLEAN_APPID:
335		af_init_app_status();
336		break;
337	case AF_CMD_SET_MAC_LIST:
338		af_set_mac_list(data_obj);
339		break;
340	default:
341		AF_ERROR("invalid cmd %d\n", cmd_obj->valueint);
342		return -1;
343	}
344	af_show_app_status();
345	return 0;
346}
347
348static int af_cdev_open(struct inode *inode, struct file *filp)
349{
350	struct af_cdev_file *file;
351	file = vzalloc(sizeof(*file));
352	if (!file)
353		return -EINVAL;
354
355	mutex_lock(&af_cdev_mutex);
356	filp->private_data = file;
357	return 0;
358}
359
360static ssize_t af_cdev_read(struct file *filp, char *buf, size_t count, loff_t *off)
361{
362	return 0;
363}
364
365static int af_cdev_release(struct inode *inode, struct file *filp)
366{
367	struct af_cdev_file *file = filp->private_data;
368	AF_DEBUG("config size: %d,data = %s\n", (int)file->size, file->buf);
369	af_config_handle(file->buf, file->size);
370	filp->private_data = NULL;
371	mutex_unlock(&af_cdev_mutex);
372	vfree(file);
373	return 0;
374}
375
376static ssize_t af_cdev_write(struct file *filp, const char *buffer, size_t count, loff_t *off)
377{
378	struct af_cdev_file *file = filp->private_data;
379	int ret;
380	if (file->size + count > sizeof(file->buf))
381	{
382		AF_ERROR("config overflow, cur_size: %d, block_size: %d, max_size: %d",
383				 (int)file->size, (int)count, (int)sizeof(file->buf));
384		return -EINVAL;
385	}
386
387	ret = copy_from_user(file->buf + file->size, buffer, count);
388	if (ret != 0)
389		return -EINVAL;
390
391	file->size += count;
392	return count;
393}
394
395static struct file_operations af_cdev_ops = {
396	owner : THIS_MODULE,
397	release : af_cdev_release,
398	open : af_cdev_open,
399	write : af_cdev_write,
400	read : af_cdev_read,
401};
402
403int af_register_dev(void)
404{
405	struct device *dev;
406	int res;
407	mutex_init(&af_cdev_mutex);
408
409	res = alloc_chrdev_region(&g_af_dev.id, 0, 1, AF_DEV_NAME);
410	if (res != 0)
411	{
412		return -EINVAL;
413	}
414
415	cdev_init(&g_af_dev.char_dev, &af_cdev_ops);
416	res = cdev_add(&g_af_dev.char_dev, g_af_dev.id, 1);
417	if (res < 0)
418	{
419		goto REGION_OUT;
420	}
421
422	g_af_dev.c = class_create(THIS_MODULE, AF_DEV_NAME);
423	if (IS_ERR_OR_NULL(g_af_dev.c))
424	{
425		goto CDEV_OUT;
426	}
427
428	dev = device_create(g_af_dev.c, NULL, g_af_dev.id, NULL, AF_DEV_NAME);
429	if (IS_ERR_OR_NULL(dev))
430	{
431		goto CLASS_OUT;
432	}
433	AF_INFO("register char dev....ok\n");
434
435	return 0;
436
437CLASS_OUT:
438	class_destroy(g_af_dev.c);
439CDEV_OUT:
440	cdev_del(&g_af_dev.char_dev);
441REGION_OUT:
442	unregister_chrdev_region(g_af_dev.id, 1);
443
444	AF_ERROR("register char dev....fail\n");
445	return -EINVAL;
446}
447
448void af_unregister_dev(void)
449{
450	device_destroy(g_af_dev.c, g_af_dev.id);
451	class_destroy(g_af_dev.c);
452	cdev_del(&g_af_dev.char_dev);
453	unregister_chrdev_region(g_af_dev.id, 1);
454	AF_INFO("unregister char dev....ok\n");
455}
456