/* * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #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; iprocess_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