/*libnl socket*/
int nl_family_id = -1;
struct nl_sock *nlSock;

int testNetlink()
{
    int err = netlink_setup();
    if(err<0){
        return err;
    }
    /*send message*/
    err = genl_send_simple(nlSock,nl_family_id,DIZ_MYFAMILY_C_GET_LEN_WATCHLIST,1,NLM_F_REQUEST);
    if(err < 0){
        LOGE("Sending neltink DIZ_MYFAMILY_C_GET_LEN_WATCHLIST message failed! %s",nl_geterror(err));
        return -1;
    }

    /*receive response*/
    int rep_len = nl_recvmsgs_default(nlSock);
    if(rep_len < 0)
    {
        LOGE("Receiving netlink DIZ_MYFAMILY_C_GET_LEN_WATCHLIST response failed: %d",nl_geterror(rep_len));
        return -1;
    }
}


void netlink_parse_watchlist_len(struct nl_msg *pMsg, void *pArg) {
    struct nlattr * attr;
    struct nlmsghdr *my_nlhdr = nlmsg_hdr(pMsg);
    struct genlmsghdr *my_genlmsghdr = genlmsg_hdr(my_nlhdr);

    attr = genlmsg_attrdata(my_genlmsghdr,0);
    size_t len = nla_get_u32(attr);

    LOGD("Kernel reports watchlist size is: %u",len);

}

int netlink_dispatch_locally(struct nl_msg *msg, void *arg)
{
    LOGD("Netlink callback called!");
    struct nlmsghdr *my_nlhdr = nlmsg_hdr(msg);
    struct genlmsghdr *my_genlmsghdr = genlmsg_hdr(my_nlhdr);


    LOGD("netlink message: len: %u , type: %hu, pid: %u ",my_nlhdr->nlmsg_len,my_nlhdr->nlmsg_type,my_nlhdr->nlmsg_pid);
    LOGD("generic netlink message: cmd %u",my_genlmsghdr->cmd);
    switch(my_genlmsghdr->cmd)
    {
        case DIZ_MYFAMILY_C_DUMP_WATCHLIST:
            LOGD("This is a DIZ_MYFAMILY_C_DUMP_WATCHLIST message");
            break;
        case DIZ_MYFAMILY_C_ADD_TO_WATCHLIST:
            LOGD("This is a DIZ_MYFAMILY_C_DUMP_WATCHLIST message");
            break;
        case DIZ_MYFAMILY_C_REMOVE_FROM_WATCHLIST:
            LOGD("This is a DIZ_MYFAMILY_C_REMOVE_FROM_WATCHLIST message");
            break;
        case DIZ_MYFAMILY_C_GET_LEN_WATCHLIST:
            LOGD("This is a DIZ_MYFAMILY_C_GET_LEN_WATCHLIST message");
            netlink_parse_watchlist_len(msg, arg);
            break;
        case DIZ_MYFAMILY_C_GET_WATCHLIST_UID:
            LOGD("This is a DIZ_MYFAMILY_C_GET_WATCHLIST_UID message");
            netlink_parse_watchlist_entry(msg, arg);
            break;
        case DIZ_MYFAMILY_C_GET_LEN_LOGFILE:
            LOGD("This is a DIZ_MYFAMILY_C_GET_LEN_LOGFILE message");
            netlink_parse_logfile_len(msg, arg);
            break;
        case DIZ_MYFAMILY_C_GET_LOGENTRY:
            LOGD("This is a DIZ_MYFAMILY_C_GET_LOGENTRY message");
            netlink_parse_logfile_entry(msg, arg);
            break;
        default:
            LOGD("Received unknown netlink command");
            return NL_SKIP;
    }
    return NL_OK;
}

int netlink_setup(void)
{
    nlSock = nl_socket_alloc();
    if(nlSock == NULL)
    {
        LOGE("Failed to allocate netlink socket");
        return -1;
    }
    LOGD("netlink socket allocated successfully. Port: %d",nl_socket_get_local_port(nlSock));

    /*register a callback to parse received messages*/
    int err = nl_socket_modify_cb(nlSock, NL_CB_VALID, NL_CB_CUSTOM, netlink_dispatch_locally, NULL);
    if(err<0)
    {
        LOGE("Failed to register netlink callback: %d",nl_geterror(err));
        return -1;
    }
    LOGD("netlink callback registered successfully");


    err = genl_connect(nlSock);
    if(err != 0)
    {
        LOGE("Failed to connect netlink socket: %s",nl_geterror(err));
        return -1;
    }

    nl_family_id = genl_ctrl_resolve(nlSock,"DIZ_MYFAMILY");
    if (nl_family_id == -1)
    {
        LOGE("Netlink family could not be resolved.");
        return -1;
    }
    LOGD("Succes resolving netlink family. We can now send messages to the kernel.");
    return 0;
}

int netlink_get_watchlist_size(void)
{
    int err;
    int hdrlen=0;
    LOGD("netlink: retrieving length of watchlist");
    if (nlSock == NULL && netlink_setup() < 0){return -1;}
    /*construct message*/
    struct nl_msg* my_msg = nlmsg_alloc();
    genlmsg_put(my_msg,NL_AUTO_PORT,NL_AUTO_SEQ,nl_family_id,hdrlen,NLM_F_REQUEST,DIZ_MYFAMILY_C_GET_LEN_WATCHLIST,1);

    /*send message*/
    err = nl_send_auto_complete(nlSock,my_msg);
    if(err < 0){
        LOGE("Sending neltink DIZ_MYFAMILY_C_GET_LEN_WATCHLIST message failed! %s",nl_geterror(err));
        return -1;
    }
    LOGD("Sending netlink DIZ_MYFAMILY_C_GET_LEN_WATCHLIST message succeded!");

    /*receive response*/
    int rep_len = nl_recvmsgs_default(nlSock);
    if(rep_len < 0)
    {
        LOGE("Receiving netlink DIZ_MYFAMILY_C_GET_LEN_WATCHLIST response failed: %d",nl_geterror(rep_len));
        return -1;
    }
    return 0;

}