xref: /linux/drivers/net/wireless/marvell/libertas/mesh.c (revision 249acb5f47df27109d74a0d904a5da56c8bac28f)
1 // SPDX-License-Identifier: GPL-2.0
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 
4 #include <linux/delay.h>
5 #include <linux/etherdevice.h>
6 #include <linux/hardirq.h>
7 #include <linux/netdevice.h>
8 #include <linux/if_ether.h>
9 #include <linux/if_arp.h>
10 #include <linux/kthread.h>
11 #include <linux/kfifo.h>
12 #include <net/cfg80211.h>
13 
14 #include "mesh.h"
15 #include "decl.h"
16 #include "cmd.h"
17 
18 
19 static int lbs_add_mesh(struct lbs_private *priv);
20 
21 /***************************************************************************
22  * Mesh command handling
23  */
24 
25 static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
26 		    struct cmd_ds_mesh_access *cmd)
27 {
28 	int ret;
29 
30 	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
31 	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
32 	cmd->hdr.result = 0;
33 
34 	cmd->action = cpu_to_le16(cmd_action);
35 
36 	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
37 
38 	return ret;
39 }
40 
41 static int __lbs_mesh_config_send(struct lbs_private *priv,
42 				  struct cmd_ds_mesh_config *cmd,
43 				  uint16_t action, uint16_t type)
44 {
45 	int ret;
46 	u16 command = CMD_MESH_CONFIG_OLD;
47 
48 	/*
49 	 * Command id is 0xac for v10 FW along with mesh interface
50 	 * id in bits 14-13-12.
51 	 */
52 	if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
53 		command = CMD_MESH_CONFIG |
54 			  (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
55 
56 	cmd->hdr.command = cpu_to_le16(command);
57 	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
58 	cmd->hdr.result = 0;
59 
60 	cmd->type = cpu_to_le16(type);
61 	cmd->action = cpu_to_le16(action);
62 
63 	ret = lbs_cmd_with_response(priv, command, cmd);
64 
65 	return ret;
66 }
67 
68 static int lbs_mesh_config_send(struct lbs_private *priv,
69 			 struct cmd_ds_mesh_config *cmd,
70 			 uint16_t action, uint16_t type)
71 {
72 	int ret;
73 
74 	if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
75 		return -EOPNOTSUPP;
76 
77 	ret = __lbs_mesh_config_send(priv, cmd, action, type);
78 	return ret;
79 }
80 
81 /* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
82  * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
83  * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
84  * lbs_mesh_config_send.
85  */
86 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
87 		uint16_t chan)
88 {
89 	struct cmd_ds_mesh_config cmd;
90 	struct mrvl_meshie *ie;
91 
92 	memset(&cmd, 0, sizeof(cmd));
93 	cmd.channel = cpu_to_le16(chan);
94 	ie = (struct mrvl_meshie *)cmd.data;
95 
96 	switch (action) {
97 	case CMD_ACT_MESH_CONFIG_START:
98 		ie->id = WLAN_EID_VENDOR_SPECIFIC;
99 		ie->val.oui[0] = 0x00;
100 		ie->val.oui[1] = 0x50;
101 		ie->val.oui[2] = 0x43;
102 		ie->val.type = MARVELL_MESH_IE_TYPE;
103 		ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
104 		ie->val.version = MARVELL_MESH_IE_VERSION;
105 		ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
106 		ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
107 		ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
108 		ie->val.mesh_id_len = priv->mesh_ssid_len;
109 		memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
110 		ie->len = sizeof(struct mrvl_meshie_val) -
111 			IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
112 		cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
113 		break;
114 	case CMD_ACT_MESH_CONFIG_STOP:
115 		break;
116 	default:
117 		return -1;
118 	}
119 	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
120 		    action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
121 		    priv->mesh_ssid);
122 
123 	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
124 }
125 
126 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
127 {
128 	priv->mesh_channel = channel;
129 	return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
130 }
131 
132 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
133 {
134 	return priv->mesh_channel ?: 1;
135 }
136 
137 /***************************************************************************
138  * Mesh sysfs support
139  */
140 
141 /*
142  * Attributes exported through sysfs
143  */
144 
145 /**
146  * lbs_anycast_get - Get function for sysfs attribute anycast_mask
147  * @dev: the &struct device
148  * @attr: device attributes
149  * @buf: buffer where data will be returned
150  */
151 static ssize_t lbs_anycast_get(struct device *dev,
152 		struct device_attribute *attr, char * buf)
153 {
154 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
155 	struct cmd_ds_mesh_access mesh_access;
156 	int ret;
157 
158 	memset(&mesh_access, 0, sizeof(mesh_access));
159 
160 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
161 	if (ret)
162 		return ret;
163 
164 	return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
165 }
166 
167 /**
168  * lbs_anycast_set - Set function for sysfs attribute anycast_mask
169  * @dev: the &struct device
170  * @attr: device attributes
171  * @buf: buffer that contains new attribute value
172  * @count: size of buffer
173  */
174 static ssize_t lbs_anycast_set(struct device *dev,
175 		struct device_attribute *attr, const char * buf, size_t count)
176 {
177 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
178 	struct cmd_ds_mesh_access mesh_access;
179 	uint32_t datum;
180 	int ret;
181 
182 	memset(&mesh_access, 0, sizeof(mesh_access));
183 	sscanf(buf, "%x", &datum);
184 	mesh_access.data[0] = cpu_to_le32(datum);
185 
186 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
187 	if (ret)
188 		return ret;
189 
190 	return strlen(buf);
191 }
192 
193 /**
194  * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
195  * @dev: the &struct device
196  * @attr: device attributes
197  * @buf: buffer where data will be returned
198  */
199 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
200 		struct device_attribute *attr, char *buf)
201 {
202 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
203 	struct cmd_ds_mesh_access mesh_access;
204 	int ret;
205 	u32 retry_limit;
206 
207 	memset(&mesh_access, 0, sizeof(mesh_access));
208 	mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
209 
210 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
211 			&mesh_access);
212 	if (ret)
213 		return ret;
214 
215 	retry_limit = le32_to_cpu(mesh_access.data[1]);
216 	return snprintf(buf, 10, "%d\n", retry_limit);
217 }
218 
219 /**
220  * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
221  * @dev: the &struct device
222  * @attr: device attributes
223  * @buf: buffer that contains new attribute value
224  * @count: size of buffer
225  */
226 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
227 		struct device_attribute *attr, const char *buf, size_t count)
228 {
229 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
230 	struct cmd_ds_mesh_access mesh_access;
231 	int ret;
232 	unsigned long retry_limit;
233 
234 	memset(&mesh_access, 0, sizeof(mesh_access));
235 	mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
236 
237 	ret = kstrtoul(buf, 10, &retry_limit);
238 	if (ret)
239 		return ret;
240 	if (retry_limit > 15)
241 		return -ENOTSUPP;
242 
243 	mesh_access.data[1] = cpu_to_le32(retry_limit);
244 
245 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
246 			&mesh_access);
247 	if (ret)
248 		return ret;
249 
250 	return strlen(buf);
251 }
252 
253 /**
254  * lbs_mesh_get - Get function for sysfs attribute mesh
255  * @dev: the &struct device
256  * @attr: device attributes
257  * @buf: buffer where data will be returned
258  */
259 static ssize_t lbs_mesh_get(struct device *dev,
260 		struct device_attribute *attr, char * buf)
261 {
262 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
263 	return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
264 }
265 
266 /**
267  * lbs_mesh_set - Set function for sysfs attribute mesh
268  * @dev: the &struct device
269  * @attr: device attributes
270  * @buf: buffer that contains new attribute value
271  * @count: size of buffer
272  */
273 static ssize_t lbs_mesh_set(struct device *dev,
274 		struct device_attribute *attr, const char * buf, size_t count)
275 {
276 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
277 	int enable;
278 
279 	sscanf(buf, "%x", &enable);
280 	enable = !!enable;
281 	if (enable == !!priv->mesh_dev)
282 		return count;
283 
284 	if (enable)
285 		lbs_add_mesh(priv);
286 	else
287 		lbs_remove_mesh(priv);
288 
289 	return count;
290 }
291 
292 /*
293  * lbs_mesh attribute to be exported per ethX interface
294  * through sysfs (/sys/class/net/ethX/lbs_mesh)
295  */
296 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
297 
298 /*
299  * anycast_mask attribute to be exported per mshX interface
300  * through sysfs (/sys/class/net/mshX/anycast_mask)
301  */
302 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
303 
304 /*
305  * prb_rsp_limit attribute to be exported per mshX interface
306  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
307  */
308 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
309 		lbs_prb_rsp_limit_set);
310 
311 static struct attribute *lbs_mesh_sysfs_entries[] = {
312 	&dev_attr_anycast_mask.attr,
313 	&dev_attr_prb_rsp_limit.attr,
314 	NULL,
315 };
316 
317 static const struct attribute_group lbs_mesh_attr_group = {
318 	.attrs = lbs_mesh_sysfs_entries,
319 };
320 
321 
322 /***************************************************************************
323  * Persistent configuration support
324  */
325 
326 static int mesh_get_default_parameters(struct device *dev,
327 				       struct mrvl_mesh_defaults *defs)
328 {
329 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
330 	struct cmd_ds_mesh_config cmd;
331 	int ret;
332 
333 	memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
334 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
335 				   CMD_TYPE_MESH_GET_DEFAULTS);
336 
337 	if (ret)
338 		return -EOPNOTSUPP;
339 
340 	memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
341 
342 	return 0;
343 }
344 
345 /**
346  * bootflag_get - Get function for sysfs attribute bootflag
347  * @dev: the &struct device
348  * @attr: device attributes
349  * @buf: buffer where data will be returned
350  */
351 static ssize_t bootflag_get(struct device *dev,
352 			    struct device_attribute *attr, char *buf)
353 {
354 	struct mrvl_mesh_defaults defs;
355 	int ret;
356 
357 	ret = mesh_get_default_parameters(dev, &defs);
358 
359 	if (ret)
360 		return ret;
361 
362 	return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
363 }
364 
365 /**
366  * bootflag_set - Set function for sysfs attribute bootflag
367  * @dev: the &struct device
368  * @attr: device attributes
369  * @buf: buffer that contains new attribute value
370  * @count: size of buffer
371  */
372 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
373 			    const char *buf, size_t count)
374 {
375 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
376 	struct cmd_ds_mesh_config cmd;
377 	uint32_t datum;
378 	int ret;
379 
380 	memset(&cmd, 0, sizeof(cmd));
381 	ret = sscanf(buf, "%d", &datum);
382 	if ((ret != 1) || (datum > 1))
383 		return -EINVAL;
384 
385 	*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
386 	cmd.length = cpu_to_le16(sizeof(uint32_t));
387 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
388 				   CMD_TYPE_MESH_SET_BOOTFLAG);
389 	if (ret)
390 		return ret;
391 
392 	return strlen(buf);
393 }
394 
395 /**
396  * boottime_get - Get function for sysfs attribute boottime
397  * @dev: the &struct device
398  * @attr: device attributes
399  * @buf: buffer where data will be returned
400  */
401 static ssize_t boottime_get(struct device *dev,
402 			    struct device_attribute *attr, char *buf)
403 {
404 	struct mrvl_mesh_defaults defs;
405 	int ret;
406 
407 	ret = mesh_get_default_parameters(dev, &defs);
408 
409 	if (ret)
410 		return ret;
411 
412 	return snprintf(buf, 12, "%d\n", defs.boottime);
413 }
414 
415 /**
416  * boottime_set - Set function for sysfs attribute boottime
417  * @dev: the &struct device
418  * @attr: device attributes
419  * @buf: buffer that contains new attribute value
420  * @count: size of buffer
421  */
422 static ssize_t boottime_set(struct device *dev,
423 		struct device_attribute *attr, const char *buf, size_t count)
424 {
425 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
426 	struct cmd_ds_mesh_config cmd;
427 	uint32_t datum;
428 	int ret;
429 
430 	memset(&cmd, 0, sizeof(cmd));
431 	ret = sscanf(buf, "%d", &datum);
432 	if ((ret != 1) || (datum > 255))
433 		return -EINVAL;
434 
435 	/* A too small boot time will result in the device booting into
436 	 * standalone (no-host) mode before the host can take control of it,
437 	 * so the change will be hard to revert.  This may be a desired
438 	 * feature (e.g to configure a very fast boot time for devices that
439 	 * will not be attached to a host), but dangerous.  So I'm enforcing a
440 	 * lower limit of 20 seconds:  remove and recompile the driver if this
441 	 * does not work for you.
442 	 */
443 	datum = (datum < 20) ? 20 : datum;
444 	cmd.data[0] = datum;
445 	cmd.length = cpu_to_le16(sizeof(uint8_t));
446 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
447 				   CMD_TYPE_MESH_SET_BOOTTIME);
448 	if (ret)
449 		return ret;
450 
451 	return strlen(buf);
452 }
453 
454 /**
455  * channel_get - Get function for sysfs attribute channel
456  * @dev: the &struct device
457  * @attr: device attributes
458  * @buf: buffer where data will be returned
459  */
460 static ssize_t channel_get(struct device *dev,
461 			   struct device_attribute *attr, char *buf)
462 {
463 	struct mrvl_mesh_defaults defs;
464 	int ret;
465 
466 	ret = mesh_get_default_parameters(dev, &defs);
467 
468 	if (ret)
469 		return ret;
470 
471 	return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
472 }
473 
474 /**
475  * channel_set - Set function for sysfs attribute channel
476  * @dev: the &struct device
477  * @attr: device attributes
478  * @buf: buffer that contains new attribute value
479  * @count: size of buffer
480  */
481 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
482 			   const char *buf, size_t count)
483 {
484 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
485 	struct cmd_ds_mesh_config cmd;
486 	uint32_t datum;
487 	int ret;
488 
489 	memset(&cmd, 0, sizeof(cmd));
490 	ret = sscanf(buf, "%d", &datum);
491 	if (ret != 1 || datum < 1 || datum > 11)
492 		return -EINVAL;
493 
494 	*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
495 	cmd.length = cpu_to_le16(sizeof(uint16_t));
496 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
497 				   CMD_TYPE_MESH_SET_DEF_CHANNEL);
498 	if (ret)
499 		return ret;
500 
501 	return strlen(buf);
502 }
503 
504 /**
505  * mesh_id_get - Get function for sysfs attribute mesh_id
506  * @dev: the &struct device
507  * @attr: device attributes
508  * @buf: buffer where data will be returned
509  */
510 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
511 			   char *buf)
512 {
513 	struct mrvl_mesh_defaults defs;
514 	int ret;
515 
516 	ret = mesh_get_default_parameters(dev, &defs);
517 
518 	if (ret)
519 		return ret;
520 
521 	if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
522 		dev_err(dev, "inconsistent mesh ID length\n");
523 		defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
524 	}
525 
526 	memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
527 	buf[defs.meshie.val.mesh_id_len] = '\n';
528 	buf[defs.meshie.val.mesh_id_len + 1] = '\0';
529 
530 	return defs.meshie.val.mesh_id_len + 1;
531 }
532 
533 /**
534  * mesh_id_set - Set function for sysfs attribute mesh_id
535  * @dev: the &struct device
536  * @attr: device attributes
537  * @buf: buffer that contains new attribute value
538  * @count: size of buffer
539  */
540 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
541 			   const char *buf, size_t count)
542 {
543 	struct cmd_ds_mesh_config cmd;
544 	struct mrvl_mesh_defaults defs;
545 	struct mrvl_meshie *ie;
546 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
547 	int len;
548 	int ret;
549 
550 	if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
551 		return -EINVAL;
552 
553 	memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
554 	ie = (struct mrvl_meshie *) &cmd.data[0];
555 
556 	/* fetch all other Information Element parameters */
557 	ret = mesh_get_default_parameters(dev, &defs);
558 
559 	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
560 
561 	/* transfer IE elements */
562 	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
563 
564 	len = count - 1;
565 	memcpy(ie->val.mesh_id, buf, len);
566 	/* SSID len */
567 	ie->val.mesh_id_len = len;
568 	/* IE len */
569 	ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
570 
571 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
572 				   CMD_TYPE_MESH_SET_MESH_IE);
573 	if (ret)
574 		return ret;
575 
576 	return strlen(buf);
577 }
578 
579 /**
580  * protocol_id_get - Get function for sysfs attribute protocol_id
581  * @dev: the &struct device
582  * @attr: device attributes
583  * @buf: buffer where data will be returned
584  */
585 static ssize_t protocol_id_get(struct device *dev,
586 			       struct device_attribute *attr, char *buf)
587 {
588 	struct mrvl_mesh_defaults defs;
589 	int ret;
590 
591 	ret = mesh_get_default_parameters(dev, &defs);
592 
593 	if (ret)
594 		return ret;
595 
596 	return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
597 }
598 
599 /**
600  * protocol_id_set - Set function for sysfs attribute protocol_id
601  * @dev: the &struct device
602  * @attr: device attributes
603  * @buf: buffer that contains new attribute value
604  * @count: size of buffer
605  */
606 static ssize_t protocol_id_set(struct device *dev,
607 		struct device_attribute *attr, const char *buf, size_t count)
608 {
609 	struct cmd_ds_mesh_config cmd;
610 	struct mrvl_mesh_defaults defs;
611 	struct mrvl_meshie *ie;
612 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
613 	uint32_t datum;
614 	int ret;
615 
616 	memset(&cmd, 0, sizeof(cmd));
617 	ret = sscanf(buf, "%d", &datum);
618 	if ((ret != 1) || (datum > 255))
619 		return -EINVAL;
620 
621 	/* fetch all other Information Element parameters */
622 	ret = mesh_get_default_parameters(dev, &defs);
623 
624 	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
625 
626 	/* transfer IE elements */
627 	ie = (struct mrvl_meshie *) &cmd.data[0];
628 	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
629 	/* update protocol id */
630 	ie->val.active_protocol_id = datum;
631 
632 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
633 				   CMD_TYPE_MESH_SET_MESH_IE);
634 	if (ret)
635 		return ret;
636 
637 	return strlen(buf);
638 }
639 
640 /**
641  * metric_id_get - Get function for sysfs attribute metric_id
642  * @dev: the &struct device
643  * @attr: device attributes
644  * @buf: buffer where data will be returned
645  */
646 static ssize_t metric_id_get(struct device *dev,
647 		struct device_attribute *attr, char *buf)
648 {
649 	struct mrvl_mesh_defaults defs;
650 	int ret;
651 
652 	ret = mesh_get_default_parameters(dev, &defs);
653 
654 	if (ret)
655 		return ret;
656 
657 	return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
658 }
659 
660 /**
661  * metric_id_set - Set function for sysfs attribute metric_id
662  * @dev: the &struct device
663  * @attr: device attributes
664  * @buf: buffer that contains new attribute value
665  * @count: size of buffer
666  */
667 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
668 			     const char *buf, size_t count)
669 {
670 	struct cmd_ds_mesh_config cmd;
671 	struct mrvl_mesh_defaults defs;
672 	struct mrvl_meshie *ie;
673 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
674 	uint32_t datum;
675 	int ret;
676 
677 	memset(&cmd, 0, sizeof(cmd));
678 	ret = sscanf(buf, "%d", &datum);
679 	if ((ret != 1) || (datum > 255))
680 		return -EINVAL;
681 
682 	/* fetch all other Information Element parameters */
683 	ret = mesh_get_default_parameters(dev, &defs);
684 
685 	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
686 
687 	/* transfer IE elements */
688 	ie = (struct mrvl_meshie *) &cmd.data[0];
689 	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
690 	/* update metric id */
691 	ie->val.active_metric_id = datum;
692 
693 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
694 				   CMD_TYPE_MESH_SET_MESH_IE);
695 	if (ret)
696 		return ret;
697 
698 	return strlen(buf);
699 }
700 
701 /**
702  * capability_get - Get function for sysfs attribute capability
703  * @dev: the &struct device
704  * @attr: device attributes
705  * @buf: buffer where data will be returned
706  */
707 static ssize_t capability_get(struct device *dev,
708 		struct device_attribute *attr, char *buf)
709 {
710 	struct mrvl_mesh_defaults defs;
711 	int ret;
712 
713 	ret = mesh_get_default_parameters(dev, &defs);
714 
715 	if (ret)
716 		return ret;
717 
718 	return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
719 }
720 
721 /**
722  * capability_set - Set function for sysfs attribute capability
723  * @dev: the &struct device
724  * @attr: device attributes
725  * @buf: buffer that contains new attribute value
726  * @count: size of buffer
727  */
728 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
729 			      const char *buf, size_t count)
730 {
731 	struct cmd_ds_mesh_config cmd;
732 	struct mrvl_mesh_defaults defs;
733 	struct mrvl_meshie *ie;
734 	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
735 	uint32_t datum;
736 	int ret;
737 
738 	memset(&cmd, 0, sizeof(cmd));
739 	ret = sscanf(buf, "%d", &datum);
740 	if ((ret != 1) || (datum > 255))
741 		return -EINVAL;
742 
743 	/* fetch all other Information Element parameters */
744 	ret = mesh_get_default_parameters(dev, &defs);
745 
746 	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
747 
748 	/* transfer IE elements */
749 	ie = (struct mrvl_meshie *) &cmd.data[0];
750 	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
751 	/* update value */
752 	ie->val.mesh_capability = datum;
753 
754 	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
755 				   CMD_TYPE_MESH_SET_MESH_IE);
756 	if (ret)
757 		return ret;
758 
759 	return strlen(buf);
760 }
761 
762 
763 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
764 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
765 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
766 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
767 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
768 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
769 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
770 
771 static struct attribute *boot_opts_attrs[] = {
772 	&dev_attr_bootflag.attr,
773 	&dev_attr_boottime.attr,
774 	&dev_attr_channel.attr,
775 	NULL
776 };
777 
778 static const struct attribute_group boot_opts_group = {
779 	.name = "boot_options",
780 	.attrs = boot_opts_attrs,
781 };
782 
783 static struct attribute *mesh_ie_attrs[] = {
784 	&dev_attr_mesh_id.attr,
785 	&dev_attr_protocol_id.attr,
786 	&dev_attr_metric_id.attr,
787 	&dev_attr_capability.attr,
788 	NULL
789 };
790 
791 static const struct attribute_group mesh_ie_group = {
792 	.name = "mesh_ie",
793 	.attrs = mesh_ie_attrs,
794 };
795 
796 static void lbs_persist_config_init(struct net_device *dev)
797 {
798 	int ret;
799 	ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
800 	if (ret)
801 		pr_err("failed to create boot_opts_group.\n");
802 
803 	ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
804 	if (ret)
805 		pr_err("failed to create mesh_ie_group.\n");
806 }
807 
808 static void lbs_persist_config_remove(struct net_device *dev)
809 {
810 	sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
811 	sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
812 }
813 
814 
815 /***************************************************************************
816  * Initializing and starting, stopping mesh
817  */
818 
819 /*
820  * Check mesh FW version and appropriately send the mesh start
821  * command
822  */
823 int lbs_init_mesh(struct lbs_private *priv)
824 {
825 	int ret = 0;
826 
827 	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
828 	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
829 	/* 5.110.22 have mesh command with 0xa3 command id */
830 	/* 10.0.0.p0 FW brings in mesh config command with different id */
831 	/* Check FW version MSB and initialize mesh_fw_ver */
832 	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
833 		/* Enable mesh, if supported, and work out which TLV it uses.
834 		   0x100 + 291 is an unofficial value used in 5.110.20.pXX
835 		   0x100 + 37 is the official value used in 5.110.21.pXX
836 		   but we check them in that order because 20.pXX doesn't
837 		   give an error -- it just silently fails. */
838 
839 		/* 5.110.20.pXX firmware will fail the command if the channel
840 		   doesn't match the existing channel. But only if the TLV
841 		   is correct. If the channel is wrong, _BOTH_ versions will
842 		   give an error to 0x100+291, and allow 0x100+37 to succeed.
843 		   It's just that 5.110.20.pXX will not have done anything
844 		   useful */
845 
846 		priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
847 		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
848 			priv->mesh_tlv = TLV_TYPE_MESH_ID;
849 			if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
850 				priv->mesh_tlv = 0;
851 		}
852 	} else
853 	if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
854 		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
855 		/* 10.0.0.pXX new firmwares should succeed with TLV
856 		 * 0x100+37; Do not invoke command with old TLV.
857 		 */
858 		priv->mesh_tlv = TLV_TYPE_MESH_ID;
859 		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
860 			priv->mesh_tlv = 0;
861 	}
862 
863 	/* Stop meshing until interface is brought up */
864 	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
865 
866 	if (priv->mesh_tlv) {
867 		sprintf(priv->mesh_ssid, "mesh");
868 		priv->mesh_ssid_len = 4;
869 		ret = 1;
870 	}
871 
872 	return ret;
873 }
874 
875 void lbs_start_mesh(struct lbs_private *priv)
876 {
877 	lbs_add_mesh(priv);
878 
879 	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
880 		netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
881 }
882 
883 int lbs_deinit_mesh(struct lbs_private *priv)
884 {
885 	struct net_device *dev = priv->dev;
886 	int ret = 0;
887 
888 	if (priv->mesh_tlv) {
889 		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
890 		ret = 1;
891 	}
892 
893 	return ret;
894 }
895 
896 
897 /**
898  * lbs_mesh_stop - close the mshX interface
899  *
900  * @dev:	A pointer to &net_device structure
901  * returns:	0
902  */
903 static int lbs_mesh_stop(struct net_device *dev)
904 {
905 	struct lbs_private *priv = dev->ml_priv;
906 
907 	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
908 		lbs_mesh_get_channel(priv));
909 
910 	spin_lock_irq(&priv->driver_lock);
911 
912 	netif_stop_queue(dev);
913 	netif_carrier_off(dev);
914 
915 	spin_unlock_irq(&priv->driver_lock);
916 
917 	lbs_update_mcast(priv);
918 	if (!lbs_iface_active(priv))
919 		lbs_stop_iface(priv);
920 
921 	return 0;
922 }
923 
924 /**
925  * lbs_mesh_dev_open - open the mshX interface
926  *
927  * @dev:	A pointer to &net_device structure
928  * returns:	0 or -EBUSY if monitor mode active
929  */
930 static int lbs_mesh_dev_open(struct net_device *dev)
931 {
932 	struct lbs_private *priv = dev->ml_priv;
933 	int ret = 0;
934 
935 	if (!priv->iface_running) {
936 		ret = lbs_start_iface(priv);
937 		if (ret)
938 			goto out;
939 	}
940 
941 	spin_lock_irq(&priv->driver_lock);
942 
943 	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
944 		ret = -EBUSY;
945 		spin_unlock_irq(&priv->driver_lock);
946 		goto out;
947 	}
948 
949 	netif_carrier_on(dev);
950 
951 	if (!priv->tx_pending_len)
952 		netif_wake_queue(dev);
953 
954 	spin_unlock_irq(&priv->driver_lock);
955 
956 	ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
957 		lbs_mesh_get_channel(priv));
958 
959 out:
960 	return ret;
961 }
962 
963 static const struct net_device_ops mesh_netdev_ops = {
964 	.ndo_open		= lbs_mesh_dev_open,
965 	.ndo_stop 		= lbs_mesh_stop,
966 	.ndo_start_xmit		= lbs_hard_start_xmit,
967 	.ndo_set_mac_address	= lbs_set_mac_address,
968 	.ndo_set_rx_mode	= lbs_set_multicast_list,
969 };
970 
971 /**
972  * lbs_add_mesh - add mshX interface
973  *
974  * @priv:	A pointer to the &struct lbs_private structure
975  * returns:	0 if successful, -X otherwise
976  */
977 static int lbs_add_mesh(struct lbs_private *priv)
978 {
979 	struct net_device *mesh_dev = NULL;
980 	struct wireless_dev *mesh_wdev;
981 	int ret = 0;
982 
983 	/* Allocate a virtual mesh device */
984 	mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
985 	if (!mesh_wdev) {
986 		lbs_deb_mesh("init mshX wireless device failed\n");
987 		ret = -ENOMEM;
988 		goto done;
989 	}
990 
991 	mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
992 	if (!mesh_dev) {
993 		lbs_deb_mesh("init mshX device failed\n");
994 		ret = -ENOMEM;
995 		goto err_free_wdev;
996 	}
997 
998 	mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
999 	mesh_wdev->wiphy = priv->wdev->wiphy;
1000 	mesh_wdev->netdev = mesh_dev;
1001 
1002 	mesh_dev->ml_priv = priv;
1003 	mesh_dev->ieee80211_ptr = mesh_wdev;
1004 	priv->mesh_dev = mesh_dev;
1005 
1006 	mesh_dev->netdev_ops = &mesh_netdev_ops;
1007 	mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1008 	eth_hw_addr_inherit(mesh_dev, priv->dev);
1009 
1010 	SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1011 
1012 	mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1013 	/* Register virtual mesh interface */
1014 	ret = register_netdev(mesh_dev);
1015 	if (ret) {
1016 		pr_err("cannot register mshX virtual interface\n");
1017 		goto err_free_netdev;
1018 	}
1019 
1020 	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1021 	if (ret)
1022 		goto err_unregister;
1023 
1024 	lbs_persist_config_init(mesh_dev);
1025 
1026 	/* Everything successful */
1027 	ret = 0;
1028 	goto done;
1029 
1030 err_unregister:
1031 	unregister_netdev(mesh_dev);
1032 
1033 err_free_netdev:
1034 	free_netdev(mesh_dev);
1035 
1036 err_free_wdev:
1037 	kfree(mesh_wdev);
1038 
1039 done:
1040 	return ret;
1041 }
1042 
1043 void lbs_remove_mesh(struct lbs_private *priv)
1044 {
1045 	struct net_device *mesh_dev;
1046 
1047 	mesh_dev = priv->mesh_dev;
1048 	if (!mesh_dev)
1049 		return;
1050 
1051 	netif_stop_queue(mesh_dev);
1052 	netif_carrier_off(mesh_dev);
1053 	sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1054 	lbs_persist_config_remove(mesh_dev);
1055 	unregister_netdev(mesh_dev);
1056 	priv->mesh_dev = NULL;
1057 	kfree(mesh_dev->ieee80211_ptr);
1058 	free_netdev(mesh_dev);
1059 }
1060 
1061 
1062 /***************************************************************************
1063  * Sending and receiving
1064  */
1065 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1066 	struct net_device *dev, struct rxpd *rxpd)
1067 {
1068 	if (priv->mesh_dev) {
1069 		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1070 			if (rxpd->rx_control & RxPD_MESH_FRAME)
1071 				dev = priv->mesh_dev;
1072 		} else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1073 			if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1074 				dev = priv->mesh_dev;
1075 		}
1076 	}
1077 	return dev;
1078 }
1079 
1080 
1081 void lbs_mesh_set_txpd(struct lbs_private *priv,
1082 	struct net_device *dev, struct txpd *txpd)
1083 {
1084 	if (dev == priv->mesh_dev) {
1085 		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1086 			txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1087 		else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1088 			txpd->u.bss.bss_num = MESH_IFACE_ID;
1089 	}
1090 }
1091 
1092 
1093 /***************************************************************************
1094  * Ethtool related
1095  */
1096 
1097 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1098 	"drop_duplicate_bcast",
1099 	"drop_ttl_zero",
1100 	"drop_no_fwd_route",
1101 	"drop_no_buffers",
1102 	"fwded_unicast_cnt",
1103 	"fwded_bcast_cnt",
1104 	"drop_blind_table",
1105 	"tx_failed_cnt"
1106 };
1107 
1108 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1109 	struct ethtool_stats *stats, uint64_t *data)
1110 {
1111 	struct lbs_private *priv = dev->ml_priv;
1112 	struct cmd_ds_mesh_access mesh_access;
1113 	int ret;
1114 
1115 	/* Get Mesh Statistics */
1116 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1117 
1118 	if (ret) {
1119 		memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1120 		return;
1121 	}
1122 
1123 	priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1124 	priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1125 	priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1126 	priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1127 	priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1128 	priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1129 	priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1130 	priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1131 
1132 	data[0] = priv->mstats.fwd_drop_rbt;
1133 	data[1] = priv->mstats.fwd_drop_ttl;
1134 	data[2] = priv->mstats.fwd_drop_noroute;
1135 	data[3] = priv->mstats.fwd_drop_nobuf;
1136 	data[4] = priv->mstats.fwd_unicast_cnt;
1137 	data[5] = priv->mstats.fwd_bcast_cnt;
1138 	data[6] = priv->mstats.drop_blind;
1139 	data[7] = priv->mstats.tx_failed_cnt;
1140 }
1141 
1142 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1143 {
1144 	struct lbs_private *priv = dev->ml_priv;
1145 
1146 	if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1147 		return MESH_STATS_NUM;
1148 
1149 	return -EOPNOTSUPP;
1150 }
1151 
1152 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1153 	uint32_t stringset, uint8_t *s)
1154 {
1155 	switch (stringset) {
1156 	case ETH_SS_STATS:
1157 		memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1158 		break;
1159 	}
1160 }
1161