#ifdef __KERNEL__

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/device.h>
#include <linux/in.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>

#include "../proc_api/proc_api.h"
#include "../../common/cJSON/cJSON.h"
#include "obj_api.h"

/**
 * @def    OBJ_DEV_NAME
 * @brief
 */
#define OBJ_DEV_NAME                    ("isg_objs")        ///< 设备节点名称

/**
 * @def    VERSION
 * @brief
 */
#define VERSION                         ("obj0.0.0.2")

/**
 * @def    SHM_MEM_SIZE
 * @brief
 */
#define SHM_MEM_SIZE                    (1024 * 1024)       ///< 1M字节共享内存

/**
 * @var typedef {anonOBJECT_DRV} OBJECT_DRV
 * @brief
 */
/**
 * @var typedef {anonOBJECT_DRV} POBJECT_DRV
 * @brief
 */
/**
 * @struct  {anonOBJECT_DRV}
 * @brief
 */
typedef struct {
    struct class       *dev_class;      ///< 设备类,用于自动在 /dev 下创建文件节点
    int                 dev_major;      ///< 设备主版本号
    atomic_t            ref_count;      ///< 驱动程序打开计数
    unsigned int        mem_size;       ///< 共享内存大小
    unsigned char      *mem_buf;        ///< 共享内存指针
} OBJECT_DRV, *POBJECT_DRV;

/**
 * @var    g_obj_device
 * @brief
 * @see    POBJECT_DRV
 */
static POBJECT_DRV g_obj_device = NULL;
DEFINE_RWLOCK(g_obj_lock);

/**
 * @var    g_obj_data
 * @brief
 * @see    PCMHI_OBJECT
 */
PCMHI_OBJECT g_obj_data = NULL;

/**
 * @brief
 *
 * @param   buf
 * @param   size
 *
 * @return
 * @date    2019/08/07
 */
void obj_upgrade_dev_buffer(unsigned char *buf, unsigned int size)
{
    if(buf && size < g_obj_device->mem_size - 1) {
        memcpy(g_obj_device->mem_buf, buf, size);
        g_obj_device->mem_buf[size] = 0;
    } else {
        printk(KERN_ERR "Buffer = %p, size = %u\n", buf, size);
    }
}

/**
 * @brief 根据对象名称获取对象
 *
 * @param   name: 对象名称
 * @param   type: 对象类型
 *
 * @return: 对象指针 或 NULL 空指针
 * @date    2019/08/07
 */
PCMHI_OBJECT get_object(const char *name, int type)
{
    PCMHI_OBJECT obj, tmp;
    PSERVER_OBJ_CONTENT req = NULL;

    HASH_FIND_STR(g_obj_data, name, obj);

    if(!obj) {
        return NULL;
    }

    if(type >= OBJ_TYPE_ADDR && type < OBJ_TYPE_MAX) {
        if(obj->type != type) {
            return NULL;
        }
    }

    return obj;
}

/**
 * @brief 判断当前服务是否在对象中
 *
 * @param   obj: 对象指针
 * @param   port: 协议端口
 * @param   proType: 协议类型
 *
 * @return: 存在:0, 不存在:1
 * @date    2019/08/07
 */
int item_belong_server_obj(PCMHI_OBJECT obj, __be16 port, int proType)
{
    PSERVER_OBJ_CONTENT req = NULL;

    if(!obj) {
        return 0;
    }

    list_for_each_entry(req, &obj->data->content, list) {
        if(proType == req->pro_type && port >= req->min_port && port <= req->max_port) {
            return 1;
        }
    }

    return 0;
}

/**
 * @brief 判断当前时间是否在对象中
 *
 * @param   obj: 对象指针
 * @param   tm: 时间戳
 *
 * @return: 存在:0, 不存在:1
 * @date    2019/08/07
 */
int item_belong_dt_obj(PCMHI_OBJECT obj, unsigned long tm)
{
    PDT_OBJ_CONTENT req = NULL;

    if(!obj) {
        return 0;
    }

    list_for_each_entry(req, &obj->data->content, list) {
        if(MODE_NONE == req->rep_mode && tm >= req->min_time && tm <= req->max_time) {
            return 1;
        }
    }

    return 0;
}

/**
 * @brief 判断IPv4地址是否在对象中
 *
 * @param   obj: 对象指针
 * @param   addr: IPv4地址
 *
 * @return: 存在:0, 不存在:1
 * @date    2019/08/07
 */
int ipv4_belong_addr_obj(PCMHI_OBJECT obj, __be32 addr)
{

}

/**
 * @brief 判断IPv6地址是否在对象中
 *
 * @param   obj: 对象指针
 * @param   addr: IPv6地址
 *
 * @return: 存在:0, 不存在:1
 * @date    2019/08/07
 */
int ipv6_belong_addr_obj(PCMHI_OBJECT obj, unsigned char addr[16])
{

}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
static int obj_proc_init(void)
{
    return server_proc_init();
}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
static int obj_proc_uninit(void)
{
    return server_proc_uninit();
}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
const char *obj_version(void)
{
    return VERSION;
}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
PCMHI_OBJECT new_object(void)
{
    PCMHI_OBJECT obj = (PCMHI_OBJECT)kmalloc(sizeof(CMHI_OBJECT), GFP_KERNEL);

    if(obj == NULL) {
        printk(KERN_ERR "Malloc CMHI_OBJECT Error\n");
    } else {
        memset(obj, 0, sizeof(CMHI_OBJECT));
        rwlock_init(&obj->lock);
        atomic_set(&obj->ref_count, 0);
    }

    return obj;
}

/**
 * @brief
 *
 * @param   pObj
 *
 * @return
 * @date    2019/08/07
 */
void free_object(PCMHI_OBJECT pObj)
{
    if(pObj) {
        kfree(pObj);
    }
}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
void object_init(void)
{
    PCMHI_OBJECT pObj = create_server_object("list1");

    if(!pObj) {
        printk(KERN_ERR "%s(%d): Create Object Error\n", __FUNCTION__, __LINE__);
        return;
    }

    HASH_ADD_STR(g_obj_data, name, pObj);

    if(add_server_obj_data(pObj, 10000, 20000, IPPROTO_IP) != 0) {
        printk(KERN_ERR "%s(%d): Add Server Object error\n", __FUNCTION__, __LINE__);
        return;
    }

    if(add_server_obj_data(pObj, 80, 80, IPPROTO_TCP) != 0) {
        printk(KERN_ERR "%s(%d): Add Server Object error\n", __FUNCTION__, __LINE__);
        return;
    }

    if(add_server_obj_data(pObj, 443, 443, IPPROTO_UDP) != 0) {
        printk(KERN_ERR "%s(%d): Add Server Object error\n", __FUNCTION__, __LINE__);
        return;
    }
}

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
void object_uninit(void)
{
    PCMHI_OBJECT obj, tmp;

    HASH_ITER(hh, g_obj_data, obj, tmp) {
        HASH_DEL(g_obj_data, obj);
        cleanup_server_object(obj);
    }
}

/**
 * @brief
 *
 * @param   inode
 * @param   filp
 *
 * @return
 * @date    2019/08/07
 */
static int obj_open(struct inode *inode, struct file *filp)
{
    // 增加引用计数
    atomic_inc(&g_obj_device->ref_count);
    return 0;
}

/**
 * @brief
 *
 * @param   inode
 * @param   filp
 *
 * @return
 * @date    2019/08/07
 */
static int obj_release(struct inode *inode, struct file *filp)
{
    // 减少引用计数
    atomic_dec(&g_obj_device->ref_count);
    return 0;
}

/**
 * @brief
 *
 * @param   fd
 * @param   vma
 *
 * @return
 * @date    2019/08/07
 */
int obj_mmap(struct file *fd, struct vm_area_struct *vma)
{
    // 重新映射内存页表
    int ret = remap_pfn_range(vma, vma->vm_start,
                              virt_to_phys(g_obj_device->mem_buf) >> PAGE_SHIFT,
                              g_obj_device->mem_size,
                              PAGE_SHARED);
    return ret;
}

/**
 * @var    obj_fops
 * @brief
 */
static struct file_operations obj_fops = {
    .open    = obj_open,
    .release = obj_release,
    .mmap    = obj_mmap,
};

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
static int object_module_init(void)
{
    struct page *p = NULL;
    dev_t dev = 0;

    printk(KERN_INFO "Hello ISG objects manager version: %s\n", VERSION);

    // 自动分配设备版本号
    if(alloc_chrdev_region(&dev, 0, 1, OBJ_DEV_NAME) != 0) {
        printk(KERN_ERR "Alloc driver dev id error\n");
        return -ENODEV;
    }

    // 分配驱动程序结构内存
    g_obj_device = (POBJECT_DRV)kmalloc(sizeof(OBJECT_DRV), GFP_KERNEL);

    if(g_obj_device == NULL) {
        printk(KERN_ERR "Create isg objects error\n");
        return -ENOMEM;
    }

    memset(g_obj_device, 0, sizeof(OBJECT_DRV));
    g_obj_device->dev_major = MAJOR(dev);           // 保存驱动版本号
    atomic_set(&g_obj_device->ref_count, 0);

    // 初始化共享内存
    g_obj_device->mem_size = PAGE_ALIGN(SHM_MEM_SIZE);
    g_obj_device->mem_buf  = (unsigned char *)__get_free_pages(GFP_KERNEL, get_order(g_obj_device->mem_size));

    if(g_obj_device->mem_buf == NULL) {
        printk(KERN_ERR "Malloc %d pages error\n", get_order(g_obj_device->mem_size));
        kfree(g_obj_device);
        return -ENOMEM;
    }

    for(p = virt_to_page(g_obj_device->mem_buf);
        p < virt_to_page(g_obj_device->mem_buf + g_obj_device->mem_size);
        p++) {
        SetPageReserved(virt_to_page(p));
    }

    memset(g_obj_device->mem_buf, 0, g_obj_device->mem_size);
    // 注册字符设备
    register_chrdev(g_obj_device->dev_major, OBJ_DEV_NAME, &obj_fops);
    // 创建字符设备类
    g_obj_device->dev_class = class_create(THIS_MODULE, "obj");
    // 创建字符设备节点
    device_create(g_obj_device->dev_class, NULL, MKDEV(g_obj_device->dev_major, 0),
                  NULL, "isg_objs/dev%d", 0);

    // 初始化 proc 接口
    obj_proc_init();
    object_init();

    return 0;
}
module_init(object_module_init);

/**
 * @brief
 *
 * @return
 * @date    2019/08/07
 */
static void __exit object_module_exit(void)
{
    struct page *p = NULL;

    printk(KERN_INFO "Bye ISG objects manager version: %s\n", VERSION);

    obj_proc_uninit();
    object_uninit();

    if(atomic_read(&g_obj_device->ref_count) != 0) {
        printk(KERN_ERR "Device used, please close it first.\n");
        return;
    }

    if(g_obj_device->mem_buf) {
        for(p = virt_to_page(g_obj_device->mem_buf);
            p < virt_to_page(g_obj_device->mem_buf + g_obj_device->mem_size);
            p++) {
            ClearPageReserved(virt_to_page(g_obj_device->mem_buf));
        }

        free_pages((unsigned long)g_obj_device->mem_buf, get_order(g_obj_device->mem_size));
    }

    device_destroy(g_obj_device->dev_class, MKDEV(g_obj_device->dev_major, 0));
    class_destroy(g_obj_device->dev_class);
    unregister_chrdev(g_obj_device->dev_major, OBJ_DEV_NAME);

    kfree(g_obj_device);
}
module_exit(object_module_exit);

MODULE_LICENSE("Dual BSD/GPL");
#endif // __KERNEL__