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