1 /*
2 * Main code of XRadio drivers
3 *
4 * Copyright (c) 2013
5 * Xradio Technology Co., Ltd. <www.xradiotech.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12 /*Linux version 3.4.0 compilation*/
13 #include <net/genetlink.h>
14 #include <net/cfg80211.h>
15 #include <linux/list.h>
16 #include <linux/list_sort.h>
17 #include <linux/timer.h>
18
19 #include "vendor.h"
20 #include "../umac/ieee80211_i.h"
21 #include "xradio.h"
22
23
24 static int xradio_vendor_do_acs(struct wiphy *wiphy,
25 struct wireless_dev *wdev,
26 const void *data, int data_len);
27
28 static int xradio_vendor_get_features(struct wiphy *wiphy,
29 struct wireless_dev *wdev,
30 const void *data, int data_len);
31
32 static int xradio_vendor_start_mkeep_alive(struct wiphy *wiphy,
33 struct wireless_dev *wdev,
34 const void *data, int data_len);
35
36 static int xradio_vendor_stop_mkeep_alive(struct wiphy *wiphy,
37 struct wireless_dev *wdev,
38 const void *data, int data_len);
39
40 static int xradio_dump_interface(struct wiphy *wiphy,
41 struct wireless_dev *wdev, struct sk_buff *skb,
42 const void *data, int data_len,
43 unsigned long *storage);
44
45 static const struct nla_policy
46 xradio_cfg80211_do_acs_policy[WLAN_VENDOR_ATTR_ACS_MAX+1] = {
47 [WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 },
48 [WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG },
49 [WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG },
50 [WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG },
51 [WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 },
52 [WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_UNSPEC },
53 [WLAN_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_UNSPEC },
54 };
55
56 static const struct nla_policy
57 xradio_cfg80211_mkeep_alive_policy[MKEEP_ALIVE_ATTRIBUTE_MAX+1] = {
58 [0] = {.type = NLA_UNSPEC },
59 [MKEEP_ALIVE_ATTRIBUTE_ID] = { .type = NLA_U8 },
60 [MKEEP_ALIVE_ATTRIBUTE_IP_PKT] = { .type = NLA_MSECS },
61 [MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN] = { .type = NLA_U16 },
62 [MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR] = { .type = NLA_MSECS,
63 .len = ETH_ALEN },
64 [MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR] = { .type = NLA_MSECS,
65 .len = ETH_ALEN },
66 [MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC] = { .type = NLA_U32 },
67 };
68
69 static const struct nla_policy
70 xradio_vendor_subcmd_set_mac_policy[WLAN_VENDOR_ATTR_DRIVER_MAX + 1] = {
71 [0] = {.type = NLA_UNSPEC },
72 [WLAN_VENDOR_ATTR_DRIVER_MAC_ADDR] = { .type = NLA_MSECS, .len = ETH_ALEN },
73 };
74
xradio_vendor_subcmd_set_mac(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)75 static int xradio_vendor_subcmd_set_mac(struct wiphy *wiphy,
76 struct wireless_dev *wdev,
77 const void *data, int data_len)
78 {
79 int ret = 0, rem, type;
80 u8 mac[ETH_ALEN];
81 const struct nlattr *iter;
82
83 nla_for_each_attr(iter, data, data_len, rem) {
84 type = nla_type(iter);
85 switch (type) {
86 case WLAN_VENDOR_ATTR_DRIVER_MAC_ADDR:
87 memcpy(mac, nla_data(iter), ETH_ALEN);
88 pr_err("%s, %02X:%02X:%02X:%02X:%02X:%02X\n", __func__,
89 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
90 break;
91 default:
92 printk("Unknown type: %d\n", type);
93 ret = -EINVAL;
94 break;
95 }
96 }
97 if (ret < 0) {
98 printk("%s is failed ret: %d\n", __func__, ret);
99 goto exit;
100 }
101
102 /* Handle mac address set here */
103
104 exit:
105 return ret;
106
107 }
108
109 static const struct wiphy_vendor_command xradio_nl80211_vendor_commands[] = {
110 [NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = {
111 .info.vendor_id = XRADIO_NL80211_VENDOR_ID,
112 .info.subcmd = NL80211_VENDOR_SUBCMD_DO_ACS,
113 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
114 WIPHY_VENDOR_CMD_NEED_RUNNING,
115 .doit = xradio_vendor_do_acs,
116 .dumpit = xradio_dump_interface,
117 .policy = xradio_cfg80211_do_acs_policy
118 },
119 [NL80211_VENDOR_SUBCMD_GET_FEATURES_INDEX] = {
120 .info.vendor_id = XRADIO_NL80211_VENDOR_ID,
121 .info.subcmd = NL80211_VENDOR_SUBCMD_GET_FEATURES,
122 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
123 WIPHY_VENDOR_CMD_NEED_RUNNING,
124 .doit = xradio_vendor_get_features,
125 .dumpit = xradio_dump_interface,
126 .policy = VENDOR_CMD_RAW_DATA
127 },
128 [NL80211_WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE_INDEX] = {
129 .info.vendor_id = XRADIO_NL80211_ANDROID_ID,
130 .info.subcmd = NL80211_WIFI_OFFLOAD_SUBCMD_START_MKEEP_ALIVE,
131 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
132 WIPHY_VENDOR_CMD_NEED_RUNNING,
133 .doit = xradio_vendor_start_mkeep_alive,
134 .dumpit = xradio_dump_interface,
135 .policy = xradio_cfg80211_mkeep_alive_policy,
136 .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
137 },
138 [NL80211_WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE_INDEX] = {
139 .info.vendor_id = XRADIO_NL80211_ANDROID_ID,
140 .info.subcmd = NL80211_WIFI_OFFLOAD_SUBCMD_STOP_MKEEP_ALIVE,
141 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
142 WIPHY_VENDOR_CMD_NEED_RUNNING,
143 .doit = xradio_vendor_stop_mkeep_alive,
144 .dumpit = xradio_dump_interface,
145 .policy = xradio_cfg80211_mkeep_alive_policy,
146 .maxattr = MKEEP_ALIVE_ATTRIBUTE_MAX
147 },
148 {
149 {
150 .vendor_id = XRADIO_NL80211_ANDROID_ID,
151 .subcmd = NL80211_VENDOR_SUBCMD_SET_MAC,
152 },
153 .flags = WIPHY_VENDOR_CMD_NEED_WDEV |
154 WIPHY_VENDOR_CMD_NEED_RUNNING,
155 .doit = xradio_vendor_subcmd_set_mac,
156 .dumpit = xradio_dump_interface,
157 .policy = xradio_vendor_subcmd_set_mac_policy,
158 .maxattr = WLAN_VENDOR_ATTR_DRIVER_MAX
159 },
160 };
161
162 /* vendor specific events */
163 static const struct nl80211_vendor_cmd_info xradio_nl80211_vendor_events[] = {
164 [NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = {
165 .vendor_id = XRADIO_NL80211_VENDOR_ID,
166 .subcmd = NL80211_VENDOR_SUBCMD_DO_ACS
167 },
168 };
169
xradio_acs_calc_channel(struct wiphy * wiphy)170 static unsigned int xradio_acs_calc_channel(struct wiphy *wiphy)
171 {
172 /*TODO: Find a better ACS algorithm*/
173 return 5;
174 }
175
176
xradio_acs_report_channel(struct wiphy * wiphy,struct wireless_dev * wdev)177 static void xradio_acs_report_channel(struct wiphy *wiphy, struct wireless_dev *wdev)
178 {
179
180 struct sk_buff *vendor_event;
181 int ret_val;
182 struct nlattr *nla;
183 u8 channel = xradio_acs_calc_channel(wiphy);
184
185 vendor_event = cfg80211_vendor_event_alloc(wiphy, NULL,
186 2 + 4 + NLMSG_HDRLEN,
187 NL80211_VENDOR_SUBCMD_DO_ACS_INDEX,
188 GFP_KERNEL);
189 if (!vendor_event) {
190 printk("cfg80211_vendor_event_alloc failed\n");
191 return;
192 }
193
194 /* Send the IF INDEX to differentiate the ACS event for each interface
195 * TODO: To be update once cfg80211 APIs are updated to accept if_index
196 */
197 nla_nest_cancel(vendor_event, ((void **)vendor_event->cb)[2]);
198
199 ret_val = nla_put_u32(vendor_event, NL80211_ATTR_IFINDEX,
200 wdev->netdev->ifindex);
201 if (ret_val) {
202 printk("NL80211_ATTR_IFINDEX put fail\n");
203 kfree_skb(vendor_event);
204 return;
205 }
206
207 nla = nla_nest_start(vendor_event, NL80211_ATTR_VENDOR_DATA);
208 ((void **)vendor_event->cb)[2] = nla;
209
210 /* channel indices used by fw are zero based and those used upper
211 * layers are 1 based: must add 1
212 */
213 ret_val = nla_put_u8(vendor_event,
214 WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
215 channel + 1);
216 if (ret_val) {
217 printk(
218 "WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail\n");
219 kfree_skb(vendor_event);
220 return;
221 }
222
223 /* must report secondary channel always, 0 is harmless */
224 ret_val = nla_put_u8(vendor_event,
225 WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, 0);
226 if (ret_val) {
227 printk(
228 "WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail\n");
229 kfree_skb(vendor_event);
230 return;
231 }
232
233 cfg80211_vendor_event(vendor_event, GFP_KERNEL);
234
235 }
236
xradio_vendor_do_acs(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)237 static int xradio_vendor_do_acs(struct wiphy *wiphy,
238 struct wireless_dev *wdev,
239 const void *data, int data_len)
240 {
241 struct sk_buff *temp_skbuff;
242 int res = 0;
243 //u8 hw_mode;
244 struct nlattr *tb[WLAN_VENDOR_ATTR_ACS_MAX + 1];
245 //struct ieee80211_channel reg_channels[ARRAY_SIZE(xradio_2ghz_chantable)];
246 //int num_channels;
247
248
249 res = nla_parse(tb, WLAN_VENDOR_ATTR_ACS_MAX, data, data_len,
250 xradio_cfg80211_do_acs_policy, NULL);
251 if (res) {
252 printk("Invalid ATTR");
253 goto out;
254 }
255
256 /*
257 if (!tb[WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
258 printk("%s: Attr hw_mode failed\n", __func__);
259 goto out;
260 }
261
262 hw_mode = nla_get_u8(tb[WLAN_VENDOR_ATTR_ACS_HW_MODE]);
263 */
264
265
266 if (tb[WLAN_VENDOR_ATTR_ACS_CH_LIST]) {
267
268 } else if (tb[WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) {
269
270 } else {
271 res = -EINVAL;
272 goto out;
273 }
274
275
276 xradio_acs_report_channel(wiphy, wdev);
277
278
279 out:
280 if (0 == res) {
281 temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
282 NLMSG_HDRLEN);
283 if (temp_skbuff)
284 return cfg80211_vendor_cmd_reply(temp_skbuff);
285 }
286
287 return res;
288 }
289
290 #define NUM_BITS_IN_BYTE 8
xradio_vendor_set_features(uint8_t * feature_flags,uint8_t feature)291 void xradio_vendor_set_features(uint8_t *feature_flags, uint8_t feature)
292 {
293 uint32_t index;
294 uint8_t bit_mask;
295
296 index = feature / NUM_BITS_IN_BYTE;
297 bit_mask = 1 << (feature % NUM_BITS_IN_BYTE);
298 feature_flags[index] |= bit_mask;
299 }
300
xradio_vendor_get_features(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)301 static int xradio_vendor_get_features(struct wiphy *wiphy,
302 struct wireless_dev *wdev,
303 const void *data, int data_len)
304 {
305 struct sk_buff *msg;
306 uint8_t feature_flags[(NUM_WLAN_VENDOR_FEATURES + 7) / 8] = {0};
307
308 xradio_vendor_set_features(feature_flags,
309 WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY);
310
311 msg = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(feature_flags) +
312 NLMSG_HDRLEN);
313 if (!msg)
314 return -ENOMEM;
315
316 if (nla_put(msg,
317 WLAN_VENDOR_ATTR_FEATURE_FLAGS,
318 sizeof(feature_flags), feature_flags))
319 goto nla_put_failure;
320
321 return cfg80211_vendor_cmd_reply(msg);
322
323 nla_put_failure:
324 kfree_skb(msg);
325 return -EINVAL;
326
327 }
328
329 struct keepalivenode {
330 struct list_head list;
331 u8 *pkt;
332 u16 pkt_len;
333 u8 id;
334 u32 period_msec;
335 unsigned long next_jiffies;
336 struct net_device *netdev;
337 };
338
339 static struct list_head keepalivelist;
340
341 struct keepalive_timer {
342 struct ieee80211_local *local;
343 struct timer_list kalive_timer;
344 };
345
346 struct keepalive_timer *keepalivetimer;
347
keep_alive_send(struct ieee80211_local * local,struct net_device * dev,u8 * frame_8023,u16 pkt_len)348 static void keep_alive_send(struct ieee80211_local *local, struct net_device *dev, u8 *frame_8023,
349 u16 pkt_len)
350 {
351 struct sk_buff *skb;
352 skb = dev_alloc_skb(local->hw.extra_tx_headroom + pkt_len);
353 if (!skb)
354 return;
355
356 skb_reserve(skb, local->hw.extra_tx_headroom);
357
358 skb_put(skb, pkt_len);
359 memcpy(skb->data, frame_8023, pkt_len);
360
361 ieee80211_subif_start_xmit(skb, dev);
362
363 }
364
365
366 static int
keep_alive_cmp(void * priv,struct list_head * a,struct list_head * b)367 keep_alive_cmp(void *priv,
368 struct list_head *a, struct list_head *b)
369 {
370 struct keepalivenode *ap = container_of(a, struct keepalivenode, list);
371 struct keepalivenode *bp = container_of(b, struct keepalivenode, list);
372 long diff;
373
374 diff = ap->next_jiffies - bp->next_jiffies;
375
376 if (diff < 0)
377 return -1;
378 if (diff > 0)
379 return 1;
380 return 0;
381 }
382
keep_alive_run(struct timer_list * t)383 static void keep_alive_run(struct timer_list *t)
384 {
385 struct keepalivenode *node;
386 struct keepalive_timer *k_timer = from_timer(k_timer, t, kalive_timer);
387 struct ieee80211_local *local = k_timer->local;
388
389 if (list_empty(&keepalivelist))
390 return;
391
392 list_for_each_entry(node, &keepalivelist, list) {
393 if (time_before(jiffies, node->next_jiffies))
394 break;
395 keep_alive_send(local, node->netdev, node->pkt, node->pkt_len);
396 node->next_jiffies += msecs_to_jiffies(node->period_msec);
397 }
398 list_sort(NULL, &keepalivelist, keep_alive_cmp);
399
400 //reset timer;
401 node = container_of(keepalivelist.next, struct keepalivenode, list);
402 mod_timer(&keepalivetimer->kalive_timer, node->next_jiffies);
403 }
404
keep_alive_queue_clear(void)405 static void keep_alive_queue_clear(void)
406 {
407 struct keepalivenode *node;
408 struct keepalivenode *tmp;
409
410 if (list_empty(&keepalivelist))
411 return;
412
413 list_for_each_entry_safe(node, tmp, &keepalivelist, list) {
414 if (node->pkt != NULL) {
415 kfree(node->pkt);
416 node->pkt = NULL;
417 }
418 list_del(&node->list);
419 kfree(node);
420 }
421
422 //delete timer
423 del_timer(&keepalivetimer->kalive_timer);
424
425 kfree(keepalivetimer);
426 }
427
keep_alive_queue_put(u8 * dst_mac,u8 * src_mac,struct net_device * netdev,u8 * ip_pkt,u16 ip_pkt_len,u32 period_msec,u8 mkeep_alive_id)428 static int keep_alive_queue_put(u8 *dst_mac, u8 *src_mac, struct net_device *netdev,
429 u8 *ip_pkt, u16 ip_pkt_len, u32 period_msec, u8 mkeep_alive_id)
430 {
431 u8 *frame_8023;
432 int len = 0;
433 int ret = 0;
434 struct keepalivenode *node;
435
436 frame_8023 = kzalloc(ip_pkt_len + 14, GFP_KERNEL);
437 if (frame_8023 == NULL) {
438 ret = -ENOMEM;
439 printk("Failed to allocate mem for frame_8023\n");
440 return ret;
441 }
442
443 node = (struct keepalivenode *)kzalloc(sizeof(struct keepalivenode), GFP_KERNEL);
444 if (node == NULL) {
445 kfree(frame_8023);
446 ret = -ENOMEM;
447 printk("Failed to allocate mem for keepalivenode\n");
448 return ret;
449 }
450
451 /*
452 * This is the IP packet, add 14 bytes Ethernet (802.3) header
453 * ------------------------------------------------------------
454 * | 14 bytes Ethernet (802.3) header | IP header and payload |
455 * ------------------------------------------------------------
456 */
457
458 /* Mapping dest mac addr */
459 memcpy(&frame_8023[len], dst_mac, ETH_ALEN);
460 len += ETH_ALEN;
461
462 /* Mapping src mac addr */
463 memcpy(&frame_8023[len], src_mac, ETH_ALEN);
464 len += ETH_ALEN;
465
466 /* Mapping Ethernet type (ETHERTYPE_IP: 0x0800) */
467 frame_8023[len] = 0x08;
468 frame_8023[len+1] = 0x00;
469 len += 2;
470
471 /* Mapping IP pkt */
472 memcpy(&frame_8023[len], ip_pkt, ip_pkt_len);
473 len += ip_pkt_len;
474
475 node->pkt = frame_8023;
476 node->pkt_len = len;
477 node->period_msec = period_msec;
478 node->id = mkeep_alive_id;
479 node->next_jiffies = jiffies;
480 node->netdev = netdev;
481
482 list_add(&node->list, &keepalivelist);
483
484 //run timer;
485 mod_timer(&keepalivetimer->kalive_timer, jiffies);
486
487 return ret;
488
489 }
490
keep_alive_queue_remove(u8 mkeep_alive_id)491 static void keep_alive_queue_remove(u8 mkeep_alive_id)
492 {
493 struct keepalivenode *node;
494 struct keepalivenode *tmp;
495
496 list_for_each_entry_safe(node, tmp, &keepalivelist, list) {
497 if (node->id == mkeep_alive_id) {
498 if (node->pkt != NULL) {
499 kfree(node->pkt);
500 node->pkt = NULL;
501 }
502 list_del(&node->list);
503 kfree(node);
504 }
505 }
506 if (list_empty(&keepalivelist)) {
507 //delete timer;
508 del_timer(&keepalivetimer->kalive_timer);
509 }
510 }
511
xradio_vendor_start_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)512 static int xradio_vendor_start_mkeep_alive(struct wiphy *wiphy,
513 struct wireless_dev *wdev,
514 const void *data, int data_len)
515 {
516 /* max size of IP packet for keep alive */
517 const int MKEEP_ALIVE_IP_PKT_MAX = 256;
518
519 int ret = 0, rem, type;
520 u8 mkeep_alive_id = 0;
521 u8 *ip_pkt = NULL;
522 u16 ip_pkt_len = 0;
523 u8 src_mac[ETH_ALEN];
524 u8 dst_mac[ETH_ALEN];
525 u32 period_msec = 0;
526 const struct nlattr *iter;
527 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
528 struct xradio_vif *priv = xrwl_get_vif_from_ieee80211(&sdata->vif);
529
530 nla_for_each_attr(iter, data, data_len, rem) {
531 type = nla_type(iter);
532 switch (type) {
533 case MKEEP_ALIVE_ATTRIBUTE_ID:
534 mkeep_alive_id = nla_get_u8(iter);
535 break;
536 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT_LEN:
537 ip_pkt_len = nla_get_u16(iter);
538 if (ip_pkt_len > MKEEP_ALIVE_IP_PKT_MAX) {
539 ret = -EINVAL;
540 goto exit;
541 }
542 break;
543 case MKEEP_ALIVE_ATTRIBUTE_IP_PKT:
544 if (!ip_pkt_len) {
545 ret = -EINVAL;
546 printk("ip packet length is 0\n");
547 goto exit;
548 }
549 ip_pkt = (u8 *)kzalloc(ip_pkt_len, GFP_KERNEL);
550 if (ip_pkt == NULL) {
551 ret = -ENOMEM;
552 printk("Failed to allocate mem for ip packet\n");
553 goto exit;
554 }
555 memcpy(ip_pkt, (u8 *)nla_data(iter), ip_pkt_len);
556 break;
557 case MKEEP_ALIVE_ATTRIBUTE_SRC_MAC_ADDR:
558 memcpy(src_mac, nla_data(iter), ETH_ALEN);
559 break;
560 case MKEEP_ALIVE_ATTRIBUTE_DST_MAC_ADDR:
561 memcpy(dst_mac, nla_data(iter), ETH_ALEN);
562 break;
563 case MKEEP_ALIVE_ATTRIBUTE_PERIOD_MSEC:
564 period_msec = nla_get_u32(iter);
565 break;
566 default:
567 printk("Unknown type: %d\n", type);
568 ret = -EINVAL;
569 goto exit;
570 }
571 }
572
573 if (ip_pkt == NULL) {
574 ret = -EINVAL;
575 printk(("ip packet is NULL\n"));
576 goto exit;
577 }
578
579 if (priv->join_status == XRADIO_JOIN_STATUS_PASSIVE) {
580 ret = -EINVAL;
581 goto exit;
582 }
583
584 ret = keep_alive_queue_put(dst_mac, src_mac, wdev->netdev,
585 ip_pkt, ip_pkt_len, period_msec, mkeep_alive_id);
586 if (ret) {
587 ret = -EINVAL;
588 goto exit;
589 }
590
591 exit:
592 if (ip_pkt) {
593 kfree(ip_pkt);
594 }
595
596 return ret;
597 }
598
xradio_vendor_stop_mkeep_alive(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)599 static int xradio_vendor_stop_mkeep_alive(struct wiphy *wiphy,
600 struct wireless_dev *wdev,
601 const void *data, int data_len)
602 {
603 int ret = 0, rem, type;
604 u8 mkeep_alive_id = 0;
605 const struct nlattr *iter;
606
607 nla_for_each_attr(iter, data, data_len, rem) {
608 type = nla_type(iter);
609 switch (type) {
610 case MKEEP_ALIVE_ATTRIBUTE_ID:
611 mkeep_alive_id = nla_get_u8(iter);
612 break;
613 default:
614 printk("Unknown type: %d\n", type);
615 ret = -EINVAL;
616 break;
617 }
618 }
619 if (ret < 0) {
620 printk("stop_mkeep_alive is failed ret: %d\n", ret);
621 goto exit;
622 }
623
624 keep_alive_queue_remove(mkeep_alive_id);
625
626 exit:
627 return ret;
628
629 }
630
xradio_dump_interface(struct wiphy * wiphy,struct wireless_dev * wdev,struct sk_buff * skb,const void * data,int data_len,unsigned long * storage)631 static int xradio_dump_interface(struct wiphy *wiphy,
632 struct wireless_dev *wdev, struct sk_buff *skb,
633 const void *data, int data_len,
634 unsigned long *storage)
635 {
636 return 0;
637 }
638
xradio_vendor_close_mkeep_alive(void)639 void xradio_vendor_close_mkeep_alive(void)
640 {
641 keep_alive_queue_clear();
642 }
643
xradio_vendor_init(struct wiphy * wiphy)644 void xradio_vendor_init(struct wiphy *wiphy)
645 {
646 struct ieee80211_local *local = wiphy_priv(wiphy);
647 /*int i = 0;
648 int *llocal = &i;*/
649
650 keepalivetimer = kmalloc(sizeof(struct keepalive_timer), GFP_KERNEL);
651 if (!keepalivetimer) {
652 printk(KERN_ERR "%s:init keepalivetimer error!\n", __func__);
653 return;
654 }
655
656 wiphy->n_vendor_commands = ARRAY_SIZE(xradio_nl80211_vendor_commands);
657 wiphy->vendor_commands = xradio_nl80211_vendor_commands;
658 wiphy->n_vendor_events = ARRAY_SIZE(xradio_nl80211_vendor_events);
659 wiphy->vendor_events = xradio_nl80211_vendor_events;
660
661 INIT_LIST_HEAD(&keepalivelist);
662 timer_setup(&keepalivetimer->kalive_timer, keep_alive_run, 0);
663 keepalivetimer->local = local;
664
665 return;
666 }
667
xr_do_gettimeofday(struct timespec64 * tv)668 void xr_do_gettimeofday(struct timespec64 *tv)
669 {
670 struct timespec64 now;
671
672 now = ktime_to_timespec64(ktime_get_boottime());
673 tv->tv_sec = now.tv_sec;
674 tv->tv_nsec = now.tv_nsec;
675 }
676
xr_get_monotonic_boottime(struct timespec64 * ts)677 void xr_get_monotonic_boottime(struct timespec64 *ts)
678 {
679 *ts = ktime_to_timespec64(ktime_get_boottime());
680 }
681
682
683
684
685