Merge tag 'chrome-platform-for-linus-4.13' of git://git.kernel.org/pub/scm/linux...
[linux/fpc-iii.git] / drivers / net / wireless / marvell / libertas / mesh.c
blob37ace5cb309d1a1b1a762c19757a0a1569a5b32b
1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3 #include <linux/delay.h>
4 #include <linux/etherdevice.h>
5 #include <linux/hardirq.h>
6 #include <linux/netdevice.h>
7 #include <linux/if_ether.h>
8 #include <linux/if_arp.h>
9 #include <linux/kthread.h>
10 #include <linux/kfifo.h>
11 #include <net/cfg80211.h>
13 #include "mesh.h"
14 #include "decl.h"
15 #include "cmd.h"
18 static int lbs_add_mesh(struct lbs_private *priv);
20 /***************************************************************************
21 * Mesh command handling
24 static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
25 struct cmd_ds_mesh_access *cmd)
27 int ret;
29 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
30 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
31 cmd->hdr.result = 0;
33 cmd->action = cpu_to_le16(cmd_action);
35 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
37 return ret;
40 static int __lbs_mesh_config_send(struct lbs_private *priv,
41 struct cmd_ds_mesh_config *cmd,
42 uint16_t action, uint16_t type)
44 int ret;
45 u16 command = CMD_MESH_CONFIG_OLD;
48 * Command id is 0xac for v10 FW along with mesh interface
49 * id in bits 14-13-12.
51 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
52 command = CMD_MESH_CONFIG |
53 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
55 cmd->hdr.command = cpu_to_le16(command);
56 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
57 cmd->hdr.result = 0;
59 cmd->type = cpu_to_le16(type);
60 cmd->action = cpu_to_le16(action);
62 ret = lbs_cmd_with_response(priv, command, cmd);
64 return ret;
67 static int lbs_mesh_config_send(struct lbs_private *priv,
68 struct cmd_ds_mesh_config *cmd,
69 uint16_t action, uint16_t type)
71 int ret;
73 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
74 return -EOPNOTSUPP;
76 ret = __lbs_mesh_config_send(priv, cmd, action, type);
77 return ret;
80 /* This function is the CMD_MESH_CONFIG legacy function. It only handles the
81 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
82 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
83 * lbs_mesh_config_send.
85 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
86 uint16_t chan)
88 struct cmd_ds_mesh_config cmd;
89 struct mrvl_meshie *ie;
91 memset(&cmd, 0, sizeof(cmd));
92 cmd.channel = cpu_to_le16(chan);
93 ie = (struct mrvl_meshie *)cmd.data;
95 switch (action) {
96 case CMD_ACT_MESH_CONFIG_START:
97 ie->id = WLAN_EID_VENDOR_SPECIFIC;
98 ie->val.oui[0] = 0x00;
99 ie->val.oui[1] = 0x50;
100 ie->val.oui[2] = 0x43;
101 ie->val.type = MARVELL_MESH_IE_TYPE;
102 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
103 ie->val.version = MARVELL_MESH_IE_VERSION;
104 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
105 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
106 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
107 ie->val.mesh_id_len = priv->mesh_ssid_len;
108 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
109 ie->len = sizeof(struct mrvl_meshie_val) -
110 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
111 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
112 break;
113 case CMD_ACT_MESH_CONFIG_STOP:
114 break;
115 default:
116 return -1;
118 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
119 action, priv->mesh_tlv, chan, priv->mesh_ssid_len,
120 priv->mesh_ssid);
122 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
125 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
127 priv->mesh_channel = channel;
128 return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
131 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
133 return priv->mesh_channel ?: 1;
136 /***************************************************************************
137 * Mesh sysfs support
141 * Attributes exported through sysfs
145 * lbs_anycast_get - Get function for sysfs attribute anycast_mask
146 * @dev: the &struct device
147 * @attr: device attributes
148 * @buf: buffer where data will be returned
150 static ssize_t lbs_anycast_get(struct device *dev,
151 struct device_attribute *attr, char * buf)
153 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
154 struct cmd_ds_mesh_access mesh_access;
155 int ret;
157 memset(&mesh_access, 0, sizeof(mesh_access));
159 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
160 if (ret)
161 return ret;
163 return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
167 * lbs_anycast_set - Set function for sysfs attribute anycast_mask
168 * @dev: the &struct device
169 * @attr: device attributes
170 * @buf: buffer that contains new attribute value
171 * @count: size of buffer
173 static ssize_t lbs_anycast_set(struct device *dev,
174 struct device_attribute *attr, const char * buf, size_t count)
176 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
177 struct cmd_ds_mesh_access mesh_access;
178 uint32_t datum;
179 int ret;
181 memset(&mesh_access, 0, sizeof(mesh_access));
182 sscanf(buf, "%x", &datum);
183 mesh_access.data[0] = cpu_to_le32(datum);
185 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
186 if (ret)
187 return ret;
189 return strlen(buf);
193 * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
194 * @dev: the &struct device
195 * @attr: device attributes
196 * @buf: buffer where data will be returned
198 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
199 struct device_attribute *attr, char *buf)
201 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
202 struct cmd_ds_mesh_access mesh_access;
203 int ret;
204 u32 retry_limit;
206 memset(&mesh_access, 0, sizeof(mesh_access));
207 mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
209 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
210 &mesh_access);
211 if (ret)
212 return ret;
214 retry_limit = le32_to_cpu(mesh_access.data[1]);
215 return snprintf(buf, 10, "%d\n", retry_limit);
219 * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
220 * @dev: the &struct device
221 * @attr: device attributes
222 * @buf: buffer that contains new attribute value
223 * @count: size of buffer
225 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
226 struct device_attribute *attr, const char *buf, size_t count)
228 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
229 struct cmd_ds_mesh_access mesh_access;
230 int ret;
231 unsigned long retry_limit;
233 memset(&mesh_access, 0, sizeof(mesh_access));
234 mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
236 ret = kstrtoul(buf, 10, &retry_limit);
237 if (ret)
238 return ret;
239 if (retry_limit > 15)
240 return -ENOTSUPP;
242 mesh_access.data[1] = cpu_to_le32(retry_limit);
244 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
245 &mesh_access);
246 if (ret)
247 return ret;
249 return strlen(buf);
253 * lbs_mesh_get - Get function for sysfs attribute mesh
254 * @dev: the &struct device
255 * @attr: device attributes
256 * @buf: buffer where data will be returned
258 static ssize_t lbs_mesh_get(struct device *dev,
259 struct device_attribute *attr, char * buf)
261 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
262 return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
266 * lbs_mesh_set - Set function for sysfs attribute mesh
267 * @dev: the &struct device
268 * @attr: device attributes
269 * @buf: buffer that contains new attribute value
270 * @count: size of buffer
272 static ssize_t lbs_mesh_set(struct device *dev,
273 struct device_attribute *attr, const char * buf, size_t count)
275 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
276 int enable;
278 sscanf(buf, "%x", &enable);
279 enable = !!enable;
280 if (enable == !!priv->mesh_dev)
281 return count;
283 if (enable)
284 lbs_add_mesh(priv);
285 else
286 lbs_remove_mesh(priv);
288 return count;
292 * lbs_mesh attribute to be exported per ethX interface
293 * through sysfs (/sys/class/net/ethX/lbs_mesh)
295 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
298 * anycast_mask attribute to be exported per mshX interface
299 * through sysfs (/sys/class/net/mshX/anycast_mask)
301 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
304 * prb_rsp_limit attribute to be exported per mshX interface
305 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
307 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
308 lbs_prb_rsp_limit_set);
310 static struct attribute *lbs_mesh_sysfs_entries[] = {
311 &dev_attr_anycast_mask.attr,
312 &dev_attr_prb_rsp_limit.attr,
313 NULL,
316 static const struct attribute_group lbs_mesh_attr_group = {
317 .attrs = lbs_mesh_sysfs_entries,
321 /***************************************************************************
322 * Persistent configuration support
325 static int mesh_get_default_parameters(struct device *dev,
326 struct mrvl_mesh_defaults *defs)
328 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
329 struct cmd_ds_mesh_config cmd;
330 int ret;
332 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
333 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
334 CMD_TYPE_MESH_GET_DEFAULTS);
336 if (ret)
337 return -EOPNOTSUPP;
339 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
341 return 0;
345 * bootflag_get - Get function for sysfs attribute bootflag
346 * @dev: the &struct device
347 * @attr: device attributes
348 * @buf: buffer where data will be returned
350 static ssize_t bootflag_get(struct device *dev,
351 struct device_attribute *attr, char *buf)
353 struct mrvl_mesh_defaults defs;
354 int ret;
356 ret = mesh_get_default_parameters(dev, &defs);
358 if (ret)
359 return ret;
361 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
365 * bootflag_set - Set function for sysfs attribute bootflag
366 * @dev: the &struct device
367 * @attr: device attributes
368 * @buf: buffer that contains new attribute value
369 * @count: size of buffer
371 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
372 const char *buf, size_t count)
374 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
375 struct cmd_ds_mesh_config cmd;
376 uint32_t datum;
377 int ret;
379 memset(&cmd, 0, sizeof(cmd));
380 ret = sscanf(buf, "%d", &datum);
381 if ((ret != 1) || (datum > 1))
382 return -EINVAL;
384 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
385 cmd.length = cpu_to_le16(sizeof(uint32_t));
386 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
387 CMD_TYPE_MESH_SET_BOOTFLAG);
388 if (ret)
389 return ret;
391 return strlen(buf);
395 * boottime_get - Get function for sysfs attribute boottime
396 * @dev: the &struct device
397 * @attr: device attributes
398 * @buf: buffer where data will be returned
400 static ssize_t boottime_get(struct device *dev,
401 struct device_attribute *attr, char *buf)
403 struct mrvl_mesh_defaults defs;
404 int ret;
406 ret = mesh_get_default_parameters(dev, &defs);
408 if (ret)
409 return ret;
411 return snprintf(buf, 12, "%d\n", defs.boottime);
415 * boottime_set - Set function for sysfs attribute boottime
416 * @dev: the &struct device
417 * @attr: device attributes
418 * @buf: buffer that contains new attribute value
419 * @count: size of buffer
421 static ssize_t boottime_set(struct device *dev,
422 struct device_attribute *attr, const char *buf, size_t count)
424 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
425 struct cmd_ds_mesh_config cmd;
426 uint32_t datum;
427 int ret;
429 memset(&cmd, 0, sizeof(cmd));
430 ret = sscanf(buf, "%d", &datum);
431 if ((ret != 1) || (datum > 255))
432 return -EINVAL;
434 /* A too small boot time will result in the device booting into
435 * standalone (no-host) mode before the host can take control of it,
436 * so the change will be hard to revert. This may be a desired
437 * feature (e.g to configure a very fast boot time for devices that
438 * will not be attached to a host), but dangerous. So I'm enforcing a
439 * lower limit of 20 seconds: remove and recompile the driver if this
440 * does not work for you.
442 datum = (datum < 20) ? 20 : datum;
443 cmd.data[0] = datum;
444 cmd.length = cpu_to_le16(sizeof(uint8_t));
445 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
446 CMD_TYPE_MESH_SET_BOOTTIME);
447 if (ret)
448 return ret;
450 return strlen(buf);
454 * channel_get - Get function for sysfs attribute channel
455 * @dev: the &struct device
456 * @attr: device attributes
457 * @buf: buffer where data will be returned
459 static ssize_t channel_get(struct device *dev,
460 struct device_attribute *attr, char *buf)
462 struct mrvl_mesh_defaults defs;
463 int ret;
465 ret = mesh_get_default_parameters(dev, &defs);
467 if (ret)
468 return ret;
470 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
474 * channel_set - Set function for sysfs attribute channel
475 * @dev: the &struct device
476 * @attr: device attributes
477 * @buf: buffer that contains new attribute value
478 * @count: size of buffer
480 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
481 const char *buf, size_t count)
483 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
484 struct cmd_ds_mesh_config cmd;
485 uint32_t datum;
486 int ret;
488 memset(&cmd, 0, sizeof(cmd));
489 ret = sscanf(buf, "%d", &datum);
490 if (ret != 1 || datum < 1 || datum > 11)
491 return -EINVAL;
493 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
494 cmd.length = cpu_to_le16(sizeof(uint16_t));
495 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
496 CMD_TYPE_MESH_SET_DEF_CHANNEL);
497 if (ret)
498 return ret;
500 return strlen(buf);
504 * mesh_id_get - Get function for sysfs attribute mesh_id
505 * @dev: the &struct device
506 * @attr: device attributes
507 * @buf: buffer where data will be returned
509 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
510 char *buf)
512 struct mrvl_mesh_defaults defs;
513 int ret;
515 ret = mesh_get_default_parameters(dev, &defs);
517 if (ret)
518 return ret;
520 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
521 dev_err(dev, "inconsistent mesh ID length\n");
522 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
525 memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
526 buf[defs.meshie.val.mesh_id_len] = '\n';
527 buf[defs.meshie.val.mesh_id_len + 1] = '\0';
529 return defs.meshie.val.mesh_id_len + 1;
533 * mesh_id_set - Set function for sysfs attribute mesh_id
534 * @dev: the &struct device
535 * @attr: device attributes
536 * @buf: buffer that contains new attribute value
537 * @count: size of buffer
539 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
540 const char *buf, size_t count)
542 struct cmd_ds_mesh_config cmd;
543 struct mrvl_mesh_defaults defs;
544 struct mrvl_meshie *ie;
545 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
546 int len;
547 int ret;
549 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
550 return -EINVAL;
552 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
553 ie = (struct mrvl_meshie *) &cmd.data[0];
555 /* fetch all other Information Element parameters */
556 ret = mesh_get_default_parameters(dev, &defs);
558 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
560 /* transfer IE elements */
561 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
563 len = count - 1;
564 memcpy(ie->val.mesh_id, buf, len);
565 /* SSID len */
566 ie->val.mesh_id_len = len;
567 /* IE len */
568 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
570 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
571 CMD_TYPE_MESH_SET_MESH_IE);
572 if (ret)
573 return ret;
575 return strlen(buf);
579 * protocol_id_get - Get function for sysfs attribute protocol_id
580 * @dev: the &struct device
581 * @attr: device attributes
582 * @buf: buffer where data will be returned
584 static ssize_t protocol_id_get(struct device *dev,
585 struct device_attribute *attr, char *buf)
587 struct mrvl_mesh_defaults defs;
588 int ret;
590 ret = mesh_get_default_parameters(dev, &defs);
592 if (ret)
593 return ret;
595 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
599 * protocol_id_set - Set function for sysfs attribute protocol_id
600 * @dev: the &struct device
601 * @attr: device attributes
602 * @buf: buffer that contains new attribute value
603 * @count: size of buffer
605 static ssize_t protocol_id_set(struct device *dev,
606 struct device_attribute *attr, const char *buf, size_t count)
608 struct cmd_ds_mesh_config cmd;
609 struct mrvl_mesh_defaults defs;
610 struct mrvl_meshie *ie;
611 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
612 uint32_t datum;
613 int ret;
615 memset(&cmd, 0, sizeof(cmd));
616 ret = sscanf(buf, "%d", &datum);
617 if ((ret != 1) || (datum > 255))
618 return -EINVAL;
620 /* fetch all other Information Element parameters */
621 ret = mesh_get_default_parameters(dev, &defs);
623 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
625 /* transfer IE elements */
626 ie = (struct mrvl_meshie *) &cmd.data[0];
627 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
628 /* update protocol id */
629 ie->val.active_protocol_id = datum;
631 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
632 CMD_TYPE_MESH_SET_MESH_IE);
633 if (ret)
634 return ret;
636 return strlen(buf);
640 * metric_id_get - Get function for sysfs attribute metric_id
641 * @dev: the &struct device
642 * @attr: device attributes
643 * @buf: buffer where data will be returned
645 static ssize_t metric_id_get(struct device *dev,
646 struct device_attribute *attr, char *buf)
648 struct mrvl_mesh_defaults defs;
649 int ret;
651 ret = mesh_get_default_parameters(dev, &defs);
653 if (ret)
654 return ret;
656 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
660 * metric_id_set - Set function for sysfs attribute metric_id
661 * @dev: the &struct device
662 * @attr: device attributes
663 * @buf: buffer that contains new attribute value
664 * @count: size of buffer
666 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
667 const char *buf, size_t count)
669 struct cmd_ds_mesh_config cmd;
670 struct mrvl_mesh_defaults defs;
671 struct mrvl_meshie *ie;
672 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
673 uint32_t datum;
674 int ret;
676 memset(&cmd, 0, sizeof(cmd));
677 ret = sscanf(buf, "%d", &datum);
678 if ((ret != 1) || (datum > 255))
679 return -EINVAL;
681 /* fetch all other Information Element parameters */
682 ret = mesh_get_default_parameters(dev, &defs);
684 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
686 /* transfer IE elements */
687 ie = (struct mrvl_meshie *) &cmd.data[0];
688 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
689 /* update metric id */
690 ie->val.active_metric_id = datum;
692 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
693 CMD_TYPE_MESH_SET_MESH_IE);
694 if (ret)
695 return ret;
697 return strlen(buf);
701 * capability_get - Get function for sysfs attribute capability
702 * @dev: the &struct device
703 * @attr: device attributes
704 * @buf: buffer where data will be returned
706 static ssize_t capability_get(struct device *dev,
707 struct device_attribute *attr, char *buf)
709 struct mrvl_mesh_defaults defs;
710 int ret;
712 ret = mesh_get_default_parameters(dev, &defs);
714 if (ret)
715 return ret;
717 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
721 * capability_set - Set function for sysfs attribute capability
722 * @dev: the &struct device
723 * @attr: device attributes
724 * @buf: buffer that contains new attribute value
725 * @count: size of buffer
727 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
728 const char *buf, size_t count)
730 struct cmd_ds_mesh_config cmd;
731 struct mrvl_mesh_defaults defs;
732 struct mrvl_meshie *ie;
733 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
734 uint32_t datum;
735 int ret;
737 memset(&cmd, 0, sizeof(cmd));
738 ret = sscanf(buf, "%d", &datum);
739 if ((ret != 1) || (datum > 255))
740 return -EINVAL;
742 /* fetch all other Information Element parameters */
743 ret = mesh_get_default_parameters(dev, &defs);
745 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
747 /* transfer IE elements */
748 ie = (struct mrvl_meshie *) &cmd.data[0];
749 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
750 /* update value */
751 ie->val.mesh_capability = datum;
753 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
754 CMD_TYPE_MESH_SET_MESH_IE);
755 if (ret)
756 return ret;
758 return strlen(buf);
762 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
763 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
764 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
765 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
766 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
767 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
768 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
770 static struct attribute *boot_opts_attrs[] = {
771 &dev_attr_bootflag.attr,
772 &dev_attr_boottime.attr,
773 &dev_attr_channel.attr,
774 NULL
777 static const struct attribute_group boot_opts_group = {
778 .name = "boot_options",
779 .attrs = boot_opts_attrs,
782 static struct attribute *mesh_ie_attrs[] = {
783 &dev_attr_mesh_id.attr,
784 &dev_attr_protocol_id.attr,
785 &dev_attr_metric_id.attr,
786 &dev_attr_capability.attr,
787 NULL
790 static const struct attribute_group mesh_ie_group = {
791 .name = "mesh_ie",
792 .attrs = mesh_ie_attrs,
795 static void lbs_persist_config_init(struct net_device *dev)
797 int ret;
798 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
799 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
802 static void lbs_persist_config_remove(struct net_device *dev)
804 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
805 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
809 /***************************************************************************
810 * Initializing and starting, stopping mesh
814 * Check mesh FW version and appropriately send the mesh start
815 * command
817 int lbs_init_mesh(struct lbs_private *priv)
819 int ret = 0;
821 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
822 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
823 /* 5.110.22 have mesh command with 0xa3 command id */
824 /* 10.0.0.p0 FW brings in mesh config command with different id */
825 /* Check FW version MSB and initialize mesh_fw_ver */
826 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
827 /* Enable mesh, if supported, and work out which TLV it uses.
828 0x100 + 291 is an unofficial value used in 5.110.20.pXX
829 0x100 + 37 is the official value used in 5.110.21.pXX
830 but we check them in that order because 20.pXX doesn't
831 give an error -- it just silently fails. */
833 /* 5.110.20.pXX firmware will fail the command if the channel
834 doesn't match the existing channel. But only if the TLV
835 is correct. If the channel is wrong, _BOTH_ versions will
836 give an error to 0x100+291, and allow 0x100+37 to succeed.
837 It's just that 5.110.20.pXX will not have done anything
838 useful */
840 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
841 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
842 priv->mesh_tlv = TLV_TYPE_MESH_ID;
843 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
844 priv->mesh_tlv = 0;
846 } else
847 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
848 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
849 /* 10.0.0.pXX new firmwares should succeed with TLV
850 * 0x100+37; Do not invoke command with old TLV.
852 priv->mesh_tlv = TLV_TYPE_MESH_ID;
853 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
854 priv->mesh_tlv = 0;
857 /* Stop meshing until interface is brought up */
858 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
860 if (priv->mesh_tlv) {
861 sprintf(priv->mesh_ssid, "mesh");
862 priv->mesh_ssid_len = 4;
863 ret = 1;
866 return ret;
869 void lbs_start_mesh(struct lbs_private *priv)
871 lbs_add_mesh(priv);
873 if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
874 netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
877 int lbs_deinit_mesh(struct lbs_private *priv)
879 struct net_device *dev = priv->dev;
880 int ret = 0;
882 if (priv->mesh_tlv) {
883 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
884 ret = 1;
887 return ret;
892 * lbs_mesh_stop - close the mshX interface
894 * @dev: A pointer to &net_device structure
895 * returns: 0
897 static int lbs_mesh_stop(struct net_device *dev)
899 struct lbs_private *priv = dev->ml_priv;
901 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
902 lbs_mesh_get_channel(priv));
904 spin_lock_irq(&priv->driver_lock);
906 netif_stop_queue(dev);
907 netif_carrier_off(dev);
909 spin_unlock_irq(&priv->driver_lock);
911 lbs_update_mcast(priv);
912 if (!lbs_iface_active(priv))
913 lbs_stop_iface(priv);
915 return 0;
919 * lbs_mesh_dev_open - open the mshX interface
921 * @dev: A pointer to &net_device structure
922 * returns: 0 or -EBUSY if monitor mode active
924 static int lbs_mesh_dev_open(struct net_device *dev)
926 struct lbs_private *priv = dev->ml_priv;
927 int ret = 0;
929 if (!priv->iface_running) {
930 ret = lbs_start_iface(priv);
931 if (ret)
932 goto out;
935 spin_lock_irq(&priv->driver_lock);
937 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
938 ret = -EBUSY;
939 spin_unlock_irq(&priv->driver_lock);
940 goto out;
943 netif_carrier_on(dev);
945 if (!priv->tx_pending_len)
946 netif_wake_queue(dev);
948 spin_unlock_irq(&priv->driver_lock);
950 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
951 lbs_mesh_get_channel(priv));
953 out:
954 return ret;
957 static const struct net_device_ops mesh_netdev_ops = {
958 .ndo_open = lbs_mesh_dev_open,
959 .ndo_stop = lbs_mesh_stop,
960 .ndo_start_xmit = lbs_hard_start_xmit,
961 .ndo_set_mac_address = lbs_set_mac_address,
962 .ndo_set_rx_mode = lbs_set_multicast_list,
966 * lbs_add_mesh - add mshX interface
968 * @priv: A pointer to the &struct lbs_private structure
969 * returns: 0 if successful, -X otherwise
971 static int lbs_add_mesh(struct lbs_private *priv)
973 struct net_device *mesh_dev = NULL;
974 struct wireless_dev *mesh_wdev;
975 int ret = 0;
977 /* Allocate a virtual mesh device */
978 mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
979 if (!mesh_wdev) {
980 lbs_deb_mesh("init mshX wireless device failed\n");
981 ret = -ENOMEM;
982 goto done;
985 mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
986 if (!mesh_dev) {
987 lbs_deb_mesh("init mshX device failed\n");
988 ret = -ENOMEM;
989 goto err_free_wdev;
992 mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
993 mesh_wdev->wiphy = priv->wdev->wiphy;
994 mesh_wdev->netdev = mesh_dev;
996 mesh_dev->ml_priv = priv;
997 mesh_dev->ieee80211_ptr = mesh_wdev;
998 priv->mesh_dev = mesh_dev;
1000 mesh_dev->netdev_ops = &mesh_netdev_ops;
1001 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1002 eth_hw_addr_inherit(mesh_dev, priv->dev);
1004 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1006 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1007 /* Register virtual mesh interface */
1008 ret = register_netdev(mesh_dev);
1009 if (ret) {
1010 pr_err("cannot register mshX virtual interface\n");
1011 goto err_free_netdev;
1014 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1015 if (ret)
1016 goto err_unregister;
1018 lbs_persist_config_init(mesh_dev);
1020 /* Everything successful */
1021 ret = 0;
1022 goto done;
1024 err_unregister:
1025 unregister_netdev(mesh_dev);
1027 err_free_netdev:
1028 free_netdev(mesh_dev);
1030 err_free_wdev:
1031 kfree(mesh_wdev);
1033 done:
1034 return ret;
1037 void lbs_remove_mesh(struct lbs_private *priv)
1039 struct net_device *mesh_dev;
1041 mesh_dev = priv->mesh_dev;
1042 if (!mesh_dev)
1043 return;
1045 netif_stop_queue(mesh_dev);
1046 netif_carrier_off(mesh_dev);
1047 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1048 lbs_persist_config_remove(mesh_dev);
1049 unregister_netdev(mesh_dev);
1050 priv->mesh_dev = NULL;
1051 kfree(mesh_dev->ieee80211_ptr);
1052 free_netdev(mesh_dev);
1056 /***************************************************************************
1057 * Sending and receiving
1059 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1060 struct net_device *dev, struct rxpd *rxpd)
1062 if (priv->mesh_dev) {
1063 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1064 if (rxpd->rx_control & RxPD_MESH_FRAME)
1065 dev = priv->mesh_dev;
1066 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1067 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1068 dev = priv->mesh_dev;
1071 return dev;
1075 void lbs_mesh_set_txpd(struct lbs_private *priv,
1076 struct net_device *dev, struct txpd *txpd)
1078 if (dev == priv->mesh_dev) {
1079 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1080 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1081 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1082 txpd->u.bss.bss_num = MESH_IFACE_ID;
1087 /***************************************************************************
1088 * Ethtool related
1091 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1092 "drop_duplicate_bcast",
1093 "drop_ttl_zero",
1094 "drop_no_fwd_route",
1095 "drop_no_buffers",
1096 "fwded_unicast_cnt",
1097 "fwded_bcast_cnt",
1098 "drop_blind_table",
1099 "tx_failed_cnt"
1102 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1103 struct ethtool_stats *stats, uint64_t *data)
1105 struct lbs_private *priv = dev->ml_priv;
1106 struct cmd_ds_mesh_access mesh_access;
1107 int ret;
1109 /* Get Mesh Statistics */
1110 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1112 if (ret) {
1113 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1114 return;
1117 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1118 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1119 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1120 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1121 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1122 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1123 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1124 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1126 data[0] = priv->mstats.fwd_drop_rbt;
1127 data[1] = priv->mstats.fwd_drop_ttl;
1128 data[2] = priv->mstats.fwd_drop_noroute;
1129 data[3] = priv->mstats.fwd_drop_nobuf;
1130 data[4] = priv->mstats.fwd_unicast_cnt;
1131 data[5] = priv->mstats.fwd_bcast_cnt;
1132 data[6] = priv->mstats.drop_blind;
1133 data[7] = priv->mstats.tx_failed_cnt;
1136 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1138 struct lbs_private *priv = dev->ml_priv;
1140 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1141 return MESH_STATS_NUM;
1143 return -EOPNOTSUPP;
1146 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1147 uint32_t stringset, uint8_t *s)
1149 switch (stringset) {
1150 case ETH_SS_STATS:
1151 memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1152 break;