1 /*
2 * Copyright (c) 2015 South Silicon Valley Microelectronics Inc.
3 * Copyright (c) 2015 iComm Corporation
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <net/sock.h>
21 #include <linux/socket.h>
22 #include <linux/net.h>
23 #include <asm/types.h>
24 #include <linux/netlink.h>
25 #include <linux/skbuff.h>
26 #include <linux/version.h>
27 #include <ssv6200.h>
28 #include "lib.h"
29 #include "dev.h"
30 #define NETLINK_SMARTLINK (31)
31 #define MAX_PAYLOAD (2048)
32 static struct sock *nl_sk = NULL;
33 struct ssv_softc *ssv_smartlink_sc = NULL;
34 EXPORT_SYMBOL(ssv_smartlink_sc);
35 u32 ssv_smartlink_status=0;
_ksmartlink_start_smartlink(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)36 static int _ksmartlink_start_smartlink(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
37 {
38 #ifdef KSMARTLINK_DEBUG
39 printk(KERN_INFO "%s\n", __FUNCTION__);
40 #endif
41 ssv_smartlink_status = 1;
42 *pOutBufLen = 0;
43 return 0;
44 }
ksmartlink_smartlink_started(void)45 int ksmartlink_smartlink_started(void)
46 {
47 return ssv_smartlink_status;
48 }
49 EXPORT_SYMBOL(ksmartlink_smartlink_started);
_ksmartlink_stop_smartlink(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)50 static int _ksmartlink_stop_smartlink(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
51 {
52 #ifdef KSMARTLINK_DEBUG
53 printk(KERN_INFO "%s\n", __FUNCTION__);
54 #endif
55 ssv_smartlink_status = 0;
56 *pOutBufLen = 0;
57 return 0;
58 }
_ksmartlink_set_channel(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)59 static int _ksmartlink_set_channel(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
60 {
61 int ret=-10;
62 int ch=(int)(*pInBuf);
63 struct ssv_softc *sc=ssv_smartlink_sc;
64 #ifdef KSMARTLINK_DEBUG
65 printk(KERN_INFO "%s %d\n", __FUNCTION__, ch);
66 #endif
67 if (!sc)
68 {
69 goto out;
70 }
71 mutex_lock(&sc->mutex);
72 ret = ssv6xxx_set_channel(sc, ch);
73 mutex_unlock(&sc->mutex);
74 *pOutBufLen = 0;
75 out:
76 return ret;
77 }
_ksmartlink_get_channel(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)78 static int _ksmartlink_get_channel(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
79 {
80 int ret=-10;
81 int ch=0;
82 struct ssv_softc *sc=ssv_smartlink_sc;
83 #ifdef KSMARTLINK_DEBUG
84 printk(KERN_INFO "%s\n", __FUNCTION__);
85 #endif
86 if (!sc)
87 {
88 goto out;
89 }
90 mutex_lock(&sc->mutex);
91 ret = ssv6xxx_get_channel(sc, &ch);
92 mutex_unlock(&sc->mutex);
93 *pOutBuf = ch;
94 *pOutBufLen = 1;
95 #ifdef KSMARTLINK_DEBUG
96 printk(KERN_INFO "%s %d\n", __FUNCTION__, ch);
97 #endif
98 out:
99 return ret;
100 }
_ksmartlink_set_promisc(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)101 static int _ksmartlink_set_promisc(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
102 {
103 int ret=-10;
104 int accept=(int)(*pInBuf);
105 struct ssv_softc *sc=ssv_smartlink_sc;
106 #ifdef KSMARTLINK_DEBUG
107 printk(KERN_INFO "%s %d\n", __FUNCTION__, accept);
108 #endif
109 if (!sc)
110 {
111 goto out;
112 }
113 mutex_lock(&sc->mutex);
114 ret = ssv6xxx_set_promisc(sc, accept);
115 mutex_unlock(&sc->mutex);
116 *pOutBufLen = 0;
117 out:
118 return ret;
119 }
_ksmartlink_get_promisc(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)120 static int _ksmartlink_get_promisc(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
121 {
122 int ret=-10;
123 int accept=(int)(*pInBuf);
124 struct ssv_softc *sc=ssv_smartlink_sc;
125 #ifdef KSMARTLINK_DEBUG
126 printk(KERN_INFO "%s\n", __FUNCTION__);
127 #endif
128 if (!sc)
129 {
130 goto out;
131 }
132 mutex_lock(&sc->mutex);
133 ret = ssv6xxx_get_promisc(sc, &accept);
134 mutex_unlock(&sc->mutex);
135 *pOutBuf = accept;
136 *pOutBufLen = 1;
137 #ifdef KSMARTLINK_DEBUG
138 printk(KERN_INFO "%s %d\n", __FUNCTION__, accept);
139 #endif
140 out:
141 return ret;
142 }
143 #define SMARTLINK_CMD_FIXED_LEN (10)
144 #define SMARTLINK_CMD_FIXED_TOT_LEN (SMARTLINK_CMD_FIXED_LEN+1)
145 #define SMARTLINK_RES_FIXED_LEN (SMARTLINK_CMD_FIXED_LEN)
146 #define SMARTLINK_RES_FIXED_TOT_LEN (SMARTLINK_RES_FIXED_LEN+2)
147 struct ksmartlink_cmd
148 {
149 char *cmd;
150 int (*process_func)(u8 *, u32, u8 *, u32 *);
151 };
152 static struct ksmartlink_cmd _ksmartlink_cmd_table[] =
153 {
154 {"startairki", _ksmartlink_start_smartlink},
155 {"stopairkis", _ksmartlink_stop_smartlink},
156 {"setchannel", _ksmartlink_set_channel},
157 {"getchannel", _ksmartlink_get_channel},
158 {"setpromisc", _ksmartlink_set_promisc},
159 {"getpromisc", _ksmartlink_get_promisc},
160 };
161 static u32 _ksmartlink_cmd_table_size=sizeof(_ksmartlink_cmd_table)/sizeof(struct ksmartlink_cmd);
162 #ifdef KSMARTLINK_DEBUG
_ksmartlink_hex_dump(u8 * pInBuf,u32 inBufLen)163 static void _ksmartlink_hex_dump(u8 *pInBuf, u32 inBufLen)
164 {
165 u32 i=0;
166 printk(KERN_INFO "\nKernel Hex Dump(len=%d):\n", inBufLen);
167 printk(KERN_INFO ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
168 for (i=0; i<inBufLen; i++)
169 {
170 if ((i) && ((i & 0xf) == 0))
171 {
172 printk("\n");
173 }
174 printk("%02x ", pInBuf[i]);
175 }
176 printk(KERN_INFO "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
177 }
178 #endif
_ksmartlink_process_msg(u8 * pInBuf,u32 inBufLen,u8 * pOutBuf,u32 * pOutBufLen)179 static int _ksmartlink_process_msg(u8 *pInBuf, u32 inBufLen, u8 *pOutBuf, u32 *pOutBufLen)
180 {
181 int ret=0;
182 u32 i=0;
183 struct ksmartlink_cmd *pCmd;
184 if (!pInBuf || !pOutBuf || !pOutBufLen)
185 {
186 printk(KERN_ERR "NULL pointer\n");
187 return -1;
188 }
189 for (i=0; i<_ksmartlink_cmd_table_size; i++)
190 {
191 if (!strncmp(_ksmartlink_cmd_table[i].cmd, pInBuf, SMARTLINK_CMD_FIXED_LEN))
192 {
193 break;
194 }
195 }
196 if (i < _ksmartlink_cmd_table_size)
197 {
198 pCmd = &_ksmartlink_cmd_table[i];
199 if (!pCmd->process_func)
200 {
201 printk(KERN_ERR "CMD %s has NULL process_func\n", pCmd->cmd);
202 return -3;
203 }
204 ret = pCmd->process_func(pInBuf+SMARTLINK_CMD_FIXED_LEN, inBufLen, pOutBuf, pOutBufLen);
205 #ifdef CONFIG_SSV_NETLINK_RESPONSE
206 if (ret < 0)
207 {
208 *pOutBufLen = SMARTLINK_RES_FIXED_TOT_LEN;
209 }
210 else
211 {
212 if (*pOutBufLen > 0)
213 {
214 pOutBuf[SMARTLINK_RES_FIXED_LEN] = (u8)ret;
215 pOutBuf[SMARTLINK_RES_FIXED_LEN+1]= *pOutBuf;
216 }
217 else
218 {
219 pOutBuf[SMARTLINK_RES_FIXED_LEN] = (u8)ret;
220 pOutBuf[SMARTLINK_RES_FIXED_LEN+1]= 0;
221 }
222 *pOutBufLen = SMARTLINK_RES_FIXED_TOT_LEN;
223 }
224 memcpy(pOutBuf, pCmd->cmd, SMARTLINK_RES_FIXED_LEN);
225 #else
226 (void)pOutBuf;
227 (void)pOutBufLen;
228 #endif
229 return 0;
230 }
231 else
232 {
233 printk(KERN_INFO "Unknow CMD or Packet?\n");
234 }
235 return 0;
236 }
237 static u8 gkBuf[MAX_PAYLOAD]={0};
238 static int ssv_usr_pid=0;
smartlink_nl_recv_msg(struct sk_buff * skb)239 void smartlink_nl_recv_msg(struct sk_buff *skb)
240 {
241 struct nlmsghdr *nlh;
242 #ifdef CONFIG_SSV_NETLINK_RESPONSE
243 struct sk_buff *skb_out;
244 #endif
245 int ret=0;
246 u8 *pInBuf=NULL;
247 u32 inBufLen=0;
248 u32 outBufLen=0;
249 nlh = (struct nlmsghdr *)skb->data;
250 ssv_usr_pid = nlh->nlmsg_pid;
251 pInBuf = (u8 *)nlmsg_data(nlh);
252 inBufLen = nlmsg_len(nlh);
253 #ifdef KSMARTLINK_DEBUG
254 _ksmartlink_hex_dump(pInBuf, inBufLen);
255 #endif
256 outBufLen = 0;
257 memset(gkBuf, 0, MAX_PAYLOAD);
258 ret = _ksmartlink_process_msg(pInBuf, inBufLen, gkBuf, &outBufLen);
259 #ifdef CONFIG_SSV_NETLINK_RESPONSE
260 if (outBufLen == 0)
261 {
262 memcpy(gkBuf, "Nothing", 8);
263 outBufLen = strlen(gkBuf);
264 }
265 skb_out = nlmsg_new(outBufLen, 0);
266 if (!skb_out)
267 {
268 printk(KERN_ERR "Failed to allocate new skb\n");
269 return;
270 }
271 nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, outBufLen, 0);
272 NETLINK_CB(skb_out).dst_group = 0;
273 memcpy(nlmsg_data(nlh), gkBuf, outBufLen);
274 ret = nlmsg_unicast(nl_sk, skb_out, ssv_usr_pid);
275 if (ret < 0)
276 {
277 printk(KERN_ERR "Error while sending bak to user\n");
278 }
279 #endif
280 return;
281 }
smartlink_nl_send_msg(struct sk_buff * skb)282 void smartlink_nl_send_msg(struct sk_buff *skb)
283 {
284 struct nlmsghdr *nlh;
285 struct sk_buff *skb_out;
286 int ret=0;
287 u8 *pOutBuf=skb->data;
288 u32 outBufLen=skb->len;
289 #ifdef KSMARTLINK_DEBUG
290 #endif
291 skb_out = nlmsg_new(outBufLen, 0);
292 if (!skb_out)
293 {
294 printk(KERN_ERR "Allocate new skb failed!\n");
295 return;
296 }
297 nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, outBufLen, 0);
298 NETLINK_CB(skb_out).dst_group = 0;
299 memcpy(nlmsg_data(nlh), pOutBuf, outBufLen);
300 ret = nlmsg_unicast(nl_sk, skb_out, ssv_usr_pid);
301 if (ret < 0)
302 {
303 printk(KERN_ERR "nlmsg_unicast failed!\n");
304 }
305 kfree_skb(skb);
306 return;
307 }
308 EXPORT_SYMBOL(smartlink_nl_send_msg);
ksmartlink_init(void)309 int ksmartlink_init(void)
310 {
311 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
312 nl_sk = netlink_kernel_create(&init_net,
313 NETLINK_SMARTLINK,
314 0,
315 smartlink_nl_recv_msg,
316 NULL,
317 THIS_MODULE);
318 #else
319 struct netlink_kernel_cfg cfg =
320 {
321 .groups = 0,
322 .input = smartlink_nl_recv_msg,
323 };
324 nl_sk = netlink_kernel_create(&init_net,
325 NETLINK_SMARTLINK,
326 &cfg);
327 #endif
328 printk(KERN_INFO "***************SmartLink Init-S**************\n");
329 if(!nl_sk)
330 {
331 printk(KERN_ERR "Error creating socket.\n");
332 return -10;
333 }
334 printk(KERN_INFO "***************SmartLink Init-E**************\n");
335 return 0;
336 }
ksmartlink_exit(void)337 void ksmartlink_exit(void)
338 {
339 printk(KERN_INFO "%s\n", __FUNCTION__);
340 if (nl_sk)
341 {
342 netlink_kernel_release(nl_sk);
343 nl_sk = NULL;
344 }
345 }
346 #if (defined(CONFIG_SSV_SUPPORT_ANDROID)||defined(CONFIG_SSV_BUILD_AS_ONE_KO))
347 EXPORT_SYMBOL(ksmartlink_init);
348 EXPORT_SYMBOL(ksmartlink_exit);
349 #else
350 module_init(ksmartlink_init);
351 module_exit(ksmartlink_exit);
352 #endif
353