• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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