Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
/*
 * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
 * Copyright (c) 2015 iComm Corporation
 *
 * This program is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
 * See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <net/sock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <ssv6200.h>
#include "lib.h"
#include "dev.h"
#define NETLINK_SMARTLINK (31)
#define MAX_PAYLOAD (2048)
static struct sock *nl_sk = NULL;
struct ssv_softc *ssv_smartlink_sc = NULL;
EXPORT_SYMBOL(ssv_smartlink_sc);
u32 ssv_smartlink_status=0;
static int _ksmartlink_start_smartlink(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s\n", __FUNCTION__);
#endif
    ssv_smartlink_status = 1;
    *pOutBufLen = 0;
    return 0;
}
int ksmartlink_smartlink_started(void)
{
    return ssv_smartlink_status;
}
EXPORT_SYMBOL(ksmartlink_smartlink_started);
static int _ksmartlink_stop_smartlink(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s\n", __FUNCTION__);
#endif
    ssv_smartlink_status = 0;
    *pOutBufLen = 0;
    return 0;
}
static int _ksmartlink_set_channel(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
    int ret=-10;
    int ch=(int)(*pInBuf);
    struct ssv_softc *sc=ssv_smartlink_sc;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s %d\n", __FUNCTION__, ch);
#endif
    if (!sc)
    {
        goto out;
    }
    mutex_lock(&sc->mutex);
    ret = ssv6xxx_set_channel(sc, ch);
    mutex_unlock(&sc->mutex);
    *pOutBufLen = 0;
out:
    return ret;
}
static int _ksmartlink_get_channel(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
    int ret=-10;
    int ch=0;
    struct ssv_softc *sc=ssv_smartlink_sc;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s\n", __FUNCTION__);
#endif
    if (!sc)
    {
        goto out;
    }
    mutex_lock(&sc->mutex);
    ret = ssv6xxx_get_channel(sc, &ch);
    mutex_unlock(&sc->mutex);
    *pOutBuf = ch;
    *pOutBufLen = 1;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s %d\n", __FUNCTION__, ch);
#endif
out:
    return ret;
}
static int _ksmartlink_set_promisc(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
    int ret=-10;
    int accept=(int)(*pInBuf);
    struct ssv_softc *sc=ssv_smartlink_sc;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s %d\n", __FUNCTION__, accept);
#endif
    if (!sc)
    {
        goto out;
    }
    mutex_lock(&sc->mutex);
    ret = ssv6xxx_set_promisc(sc, accept);
    mutex_unlock(&sc->mutex);
    *pOutBufLen = 0;
out:
    return ret;
}
static int _ksmartlink_get_promisc(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
    int ret=-10;
    int accept=(int)(*pInBuf);
    struct ssv_softc *sc=ssv_smartlink_sc;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s\n", __FUNCTION__);
#endif
    if (!sc)
    {
        goto out;
    }
    mutex_lock(&sc->mutex);
    ret = ssv6xxx_get_promisc(sc, &accept);
    mutex_unlock(&sc->mutex);
    *pOutBuf = accept;
    *pOutBufLen = 1;
#ifdef KSMARTLINK_DEBUG
    printk(KERN_INFO "%s %d\n", __FUNCTION__, accept);
#endif
out:
    return ret;
}
#define SMARTLINK_CMD_FIXED_LEN (10)
#define SMARTLINK_CMD_FIXED_TOT_LEN (SMARTLINK_CMD_FIXED_LEN+1)
#define SMARTLINK_RES_FIXED_LEN (SMARTLINK_CMD_FIXED_LEN)
#define SMARTLINK_RES_FIXED_TOT_LEN (SMARTLINK_RES_FIXED_LEN+2)
struct ksmartlink_cmd
{
    char *cmd;
    int (*process_func)(u8 *, u32, u8 *, u32 *);
};
static struct ksmartlink_cmd _ksmartlink_cmd_table[] =
{
    {"startairki", _ksmartlink_start_smartlink},
    {"stopairkis", _ksmartlink_stop_smartlink},
    {"setchannel", _ksmartlink_set_channel},
    {"getchannel", _ksmartlink_get_channel},
    {"setpromisc", _ksmartlink_set_promisc},
    {"getpromisc", _ksmartlink_get_promisc},
};
static u32 _ksmartlink_cmd_table_size=sizeof(_ksmartlink_cmd_table)/sizeof(struct ksmartlink_cmd);
#ifdef KSMARTLINK_DEBUG
static void _ksmartlink_hex_dump(u8 *pInBuf, u32 inBufLen)
{
    u32 i=0;
    printk(KERN_INFO "\nKernel Hex Dump(len=%d):\n", inBufLen);
    printk(KERN_INFO ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
    for (i=0; i<inBufLen; i++)
    {
        if ((i) && ((i & 0xf) == 0))
        {
            printk("\n");
        }
        printk("%02x ", pInBuf[i]);
    }
    printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
}
#endif
static int _ksmartlink_process_msg(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
{
    int ret=0;
    u32 i=0;
    struct ksmartlink_cmd *pCmd;
    if (!pInBuf || !pOutBuf || !pOutBufLen)
    {
        printk(KERN_ERR "NULL pointer\n");
        return -1;
    }
    for (i=0; i<_ksmartlink_cmd_table_size; i++)
    {
        if (!strncmp(_ksmartlink_cmd_table[i].cmd, pInBuf, SMARTLINK_CMD_FIXED_LEN))
        {
            break;
        }
    }
    if (i < _ksmartlink_cmd_table_size)
    {
        pCmd = &_ksmartlink_cmd_table[i];
        if (!pCmd->process_func)
        {
            printk(KERN_ERR "CMD %s has NULL process_func\n", pCmd->cmd);
            return -3;
        }
        ret = pCmd->process_func(pInBuf+SMARTLINK_CMD_FIXED_LEN, inBufLen, pOutBuf, pOutBufLen);
    #ifdef CONFIG_SSV_NETLINK_RESPONSE
        if (ret < 0)
        {
            *pOutBufLen = SMARTLINK_RES_FIXED_TOT_LEN;
        }
        else
        {
            if (*pOutBufLen > 0)
            {
                pOutBuf[SMARTLINK_RES_FIXED_LEN] = (u8)ret;
                pOutBuf[SMARTLINK_RES_FIXED_LEN+1]= *pOutBuf;
            }
            else
            {
                pOutBuf[SMARTLINK_RES_FIXED_LEN] = (u8)ret;
                pOutBuf[SMARTLINK_RES_FIXED_LEN+1]= 0;
            }
            *pOutBufLen = SMARTLINK_RES_FIXED_TOT_LEN;
        }
        memcpy(pOutBuf, pCmd->cmd, SMARTLINK_RES_FIXED_LEN);
    #else
        (void)pOutBuf;
        (void)pOutBufLen;
    #endif
        return 0;
    }
    else
    {
        printk(KERN_INFO "Unknow CMD or Packet?\n");
    }
    return 0;
}
static u8 gkBuf[MAX_PAYLOAD]={0};
static int ssv_usr_pid=0;
void smartlink_nl_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
#ifdef CONFIG_SSV_NETLINK_RESPONSE
    struct sk_buff *skb_out;
#endif
    int ret=0;
    u8 *pInBuf=NULL;
    u32 inBufLen=0;
    u32 outBufLen=0;
    nlh = (struct nlmsghdr *)skb->data;
    ssv_usr_pid = nlh->nlmsg_pid;
    pInBuf = (u8 *)nlmsg_data(nlh);
    inBufLen = nlmsg_len(nlh);
    #ifdef KSMARTLINK_DEBUG
    _ksmartlink_hex_dump(pInBuf, inBufLen);
    #endif
    outBufLen = 0;
    memset(gkBuf, 0, MAX_PAYLOAD);
    ret = _ksmartlink_process_msg(pInBuf, inBufLen, gkBuf, &outBufLen);
#ifdef CONFIG_SSV_NETLINK_RESPONSE
    if (outBufLen == 0)
    {
        memcpy(gkBuf, "Nothing", 8);
        outBufLen = strlen(gkBuf);
    }
    skb_out = nlmsg_new(outBufLen, 0);
    if (!skb_out)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");
        return;
    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, outBufLen, 0);
    NETLINK_CB(skb_out).dst_group = 0;
    memcpy(nlmsg_data(nlh), gkBuf, outBufLen);
    ret = nlmsg_unicast(nl_sk, skb_out, ssv_usr_pid);
    if (ret < 0)
    {
        printk(KERN_ERR "Error while sending bak to user\n");
    }
#endif
    return;
}
void smartlink_nl_send_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh;
    struct sk_buff *skb_out;
    int ret=0;
    u8 *pOutBuf=skb->data;
    u32 outBufLen=skb->len;
    #ifdef KSMARTLINK_DEBUG
    #endif
    skb_out = nlmsg_new(outBufLen, 0);
    if (!skb_out)
    {
        printk(KERN_ERR "Allocate new skb failed!\n");
        return;
    }
    nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, outBufLen, 0);
    NETLINK_CB(skb_out).dst_group = 0;
    memcpy(nlmsg_data(nlh), pOutBuf, outBufLen);
    ret = nlmsg_unicast(nl_sk, skb_out, ssv_usr_pid);
    if (ret < 0)
    {
        printk(KERN_ERR "nlmsg_unicast failed!\n");
    }
    kfree_skb(skb);
    return;
}
EXPORT_SYMBOL(smartlink_nl_send_msg);
int ksmartlink_init(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
    nl_sk = netlink_kernel_create(&init_net,
                                  NETLINK_SMARTLINK,
                                  0,
                                  smartlink_nl_recv_msg,
                                  NULL,
                                  THIS_MODULE);
#else
    struct netlink_kernel_cfg cfg =
            {
                .groups = 0,
                .input = smartlink_nl_recv_msg,
            };
    nl_sk = netlink_kernel_create(&init_net,
                                  NETLINK_SMARTLINK,
                                  &cfg);
#endif
    printk(KERN_INFO "***************SmartLink Init-S**************\n");
    if(!nl_sk)
    {
        printk(KERN_ERR "Error creating socket.\n");
        return -10;
    }
    printk(KERN_INFO "***************SmartLink Init-E**************\n");
    return 0;
}
void ksmartlink_exit(void)
{
    printk(KERN_INFO "%s\n", __FUNCTION__);
    if (nl_sk)
    {
        netlink_kernel_release(nl_sk);
        nl_sk = NULL;
    }
}
#if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
EXPORT_SYMBOL(ksmartlink_init);
EXPORT_SYMBOL(ksmartlink_exit);
#else
module_init(ksmartlink_init);
module_exit(ksmartlink_exit);
#endif