xref: /linux/drivers/net/wireless/marvell/libertas/mesh.c (revision 8a103df440afea30c91ebd42e61dc644e647f4bd)
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 	ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
801 }
802 
803 static void lbs_persist_config_remove(struct net_device *dev)
804 {
805 	sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
806 	sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
807 }
808 
809 
810 /***************************************************************************
811  * Initializing and starting, stopping mesh
812  */
813 
814 /*
815  * Check mesh FW version and appropriately send the mesh start
816  * command
817  */
818 int lbs_init_mesh(struct lbs_private *priv)
819 {
820 	int ret = 0;
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 	if (priv->mesh_tlv) {
862 		sprintf(priv->mesh_ssid, "mesh");
863 		priv->mesh_ssid_len = 4;
864 		ret = 1;
865 	}
866 
867 	return ret;
868 }
869 
870 void lbs_start_mesh(struct lbs_private *priv)
871 {
872 	lbs_add_mesh(priv);
873 
874 	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
875 		netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
876 }
877 
878 int lbs_deinit_mesh(struct lbs_private *priv)
879 {
880 	struct net_device *dev = priv->dev;
881 	int ret = 0;
882 
883 	if (priv->mesh_tlv) {
884 		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
885 		ret = 1;
886 	}
887 
888 	return ret;
889 }
890 
891 
892 /**
893  * lbs_mesh_stop - close the mshX interface
894  *
895  * @dev:	A pointer to &net_device structure
896  * returns:	0
897  */
898 static int lbs_mesh_stop(struct net_device *dev)
899 {
900 	struct lbs_private *priv = dev->ml_priv;
901 
902 	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
903 		lbs_mesh_get_channel(priv));
904 
905 	spin_lock_irq(&priv->driver_lock);
906 
907 	netif_stop_queue(dev);
908 	netif_carrier_off(dev);
909 
910 	spin_unlock_irq(&priv->driver_lock);
911 
912 	lbs_update_mcast(priv);
913 	if (!lbs_iface_active(priv))
914 		lbs_stop_iface(priv);
915 
916 	return 0;
917 }
918 
919 /**
920  * lbs_mesh_dev_open - open the mshX interface
921  *
922  * @dev:	A pointer to &net_device structure
923  * returns:	0 or -EBUSY if monitor mode active
924  */
925 static int lbs_mesh_dev_open(struct net_device *dev)
926 {
927 	struct lbs_private *priv = dev->ml_priv;
928 	int ret = 0;
929 
930 	if (!priv->iface_running) {
931 		ret = lbs_start_iface(priv);
932 		if (ret)
933 			goto out;
934 	}
935 
936 	spin_lock_irq(&priv->driver_lock);
937 
938 	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
939 		ret = -EBUSY;
940 		spin_unlock_irq(&priv->driver_lock);
941 		goto out;
942 	}
943 
944 	netif_carrier_on(dev);
945 
946 	if (!priv->tx_pending_len)
947 		netif_wake_queue(dev);
948 
949 	spin_unlock_irq(&priv->driver_lock);
950 
951 	ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
952 		lbs_mesh_get_channel(priv));
953 
954 out:
955 	return ret;
956 }
957 
958 static const struct net_device_ops mesh_netdev_ops = {
959 	.ndo_open		= lbs_mesh_dev_open,
960 	.ndo_stop 		= lbs_mesh_stop,
961 	.ndo_start_xmit		= lbs_hard_start_xmit,
962 	.ndo_set_mac_address	= lbs_set_mac_address,
963 	.ndo_set_rx_mode	= lbs_set_multicast_list,
964 };
965 
966 /**
967  * lbs_add_mesh - add mshX interface
968  *
969  * @priv:	A pointer to the &struct lbs_private structure
970  * returns:	0 if successful, -X otherwise
971  */
972 static int lbs_add_mesh(struct lbs_private *priv)
973 {
974 	struct net_device *mesh_dev = NULL;
975 	struct wireless_dev *mesh_wdev;
976 	int ret = 0;
977 
978 	/* Allocate a virtual mesh device */
979 	mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
980 	if (!mesh_wdev) {
981 		lbs_deb_mesh("init mshX wireless device failed\n");
982 		ret = -ENOMEM;
983 		goto done;
984 	}
985 
986 	mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
987 	if (!mesh_dev) {
988 		lbs_deb_mesh("init mshX device failed\n");
989 		ret = -ENOMEM;
990 		goto err_free_wdev;
991 	}
992 
993 	mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
994 	mesh_wdev->wiphy = priv->wdev->wiphy;
995 	mesh_wdev->netdev = mesh_dev;
996 
997 	mesh_dev->ml_priv = priv;
998 	mesh_dev->ieee80211_ptr = mesh_wdev;
999 	priv->mesh_dev = mesh_dev;
1000 
1001 	mesh_dev->netdev_ops = &mesh_netdev_ops;
1002 	mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1003 	eth_hw_addr_inherit(mesh_dev, priv->dev);
1004 
1005 	SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1006 
1007 	mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1008 	/* Register virtual mesh interface */
1009 	ret = register_netdev(mesh_dev);
1010 	if (ret) {
1011 		pr_err("cannot register mshX virtual interface\n");
1012 		goto err_free_netdev;
1013 	}
1014 
1015 	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1016 	if (ret)
1017 		goto err_unregister;
1018 
1019 	lbs_persist_config_init(mesh_dev);
1020 
1021 	/* Everything successful */
1022 	ret = 0;
1023 	goto done;
1024 
1025 err_unregister:
1026 	unregister_netdev(mesh_dev);
1027 
1028 err_free_netdev:
1029 	free_netdev(mesh_dev);
1030 
1031 err_free_wdev:
1032 	kfree(mesh_wdev);
1033 
1034 done:
1035 	return ret;
1036 }
1037 
1038 void lbs_remove_mesh(struct lbs_private *priv)
1039 {
1040 	struct net_device *mesh_dev;
1041 
1042 	mesh_dev = priv->mesh_dev;
1043 	if (!mesh_dev)
1044 		return;
1045 
1046 	netif_stop_queue(mesh_dev);
1047 	netif_carrier_off(mesh_dev);
1048 	sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1049 	lbs_persist_config_remove(mesh_dev);
1050 	unregister_netdev(mesh_dev);
1051 	priv->mesh_dev = NULL;
1052 	kfree(mesh_dev->ieee80211_ptr);
1053 	free_netdev(mesh_dev);
1054 }
1055 
1056 
1057 /***************************************************************************
1058  * Sending and receiving
1059  */
1060 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1061 	struct net_device *dev, struct rxpd *rxpd)
1062 {
1063 	if (priv->mesh_dev) {
1064 		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1065 			if (rxpd->rx_control & RxPD_MESH_FRAME)
1066 				dev = priv->mesh_dev;
1067 		} else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1068 			if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1069 				dev = priv->mesh_dev;
1070 		}
1071 	}
1072 	return dev;
1073 }
1074 
1075 
1076 void lbs_mesh_set_txpd(struct lbs_private *priv,
1077 	struct net_device *dev, struct txpd *txpd)
1078 {
1079 	if (dev == priv->mesh_dev) {
1080 		if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1081 			txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1082 		else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1083 			txpd->u.bss.bss_num = MESH_IFACE_ID;
1084 	}
1085 }
1086 
1087 
1088 /***************************************************************************
1089  * Ethtool related
1090  */
1091 
1092 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1093 	"drop_duplicate_bcast",
1094 	"drop_ttl_zero",
1095 	"drop_no_fwd_route",
1096 	"drop_no_buffers",
1097 	"fwded_unicast_cnt",
1098 	"fwded_bcast_cnt",
1099 	"drop_blind_table",
1100 	"tx_failed_cnt"
1101 };
1102 
1103 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1104 	struct ethtool_stats *stats, uint64_t *data)
1105 {
1106 	struct lbs_private *priv = dev->ml_priv;
1107 	struct cmd_ds_mesh_access mesh_access;
1108 	int ret;
1109 
1110 	/* Get Mesh Statistics */
1111 	ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1112 
1113 	if (ret) {
1114 		memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1115 		return;
1116 	}
1117 
1118 	priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1119 	priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1120 	priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1121 	priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1122 	priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1123 	priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1124 	priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1125 	priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1126 
1127 	data[0] = priv->mstats.fwd_drop_rbt;
1128 	data[1] = priv->mstats.fwd_drop_ttl;
1129 	data[2] = priv->mstats.fwd_drop_noroute;
1130 	data[3] = priv->mstats.fwd_drop_nobuf;
1131 	data[4] = priv->mstats.fwd_unicast_cnt;
1132 	data[5] = priv->mstats.fwd_bcast_cnt;
1133 	data[6] = priv->mstats.drop_blind;
1134 	data[7] = priv->mstats.tx_failed_cnt;
1135 }
1136 
1137 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1138 {
1139 	struct lbs_private *priv = dev->ml_priv;
1140 
1141 	if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1142 		return MESH_STATS_NUM;
1143 
1144 	return -EOPNOTSUPP;
1145 }
1146 
1147 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1148 	uint32_t stringset, uint8_t *s)
1149 {
1150 	switch (stringset) {
1151 	case ETH_SS_STATS:
1152 		memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1153 		break;
1154 	}
1155 }
1156