net: ptp: do not reimplement PTP/BPF classifier
[linux/fpc-iii.git] / drivers / net / wireless / libertas / mesh.c
blob6fef746345bc5ddd16957ad0d69a42a1f4636903
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 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
31 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
32 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
33 cmd->hdr.result = 0;
35 cmd->action = cpu_to_le16(cmd_action);
37 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
39 lbs_deb_leave(LBS_DEB_CMD);
40 return ret;
43 static int __lbs_mesh_config_send(struct lbs_private *priv,
44 struct cmd_ds_mesh_config *cmd,
45 uint16_t action, uint16_t type)
47 int ret;
48 u16 command = CMD_MESH_CONFIG_OLD;
50 lbs_deb_enter(LBS_DEB_CMD);
53 * Command id is 0xac for v10 FW along with mesh interface
54 * id in bits 14-13-12.
56 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
57 command = CMD_MESH_CONFIG |
58 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
60 cmd->hdr.command = cpu_to_le16(command);
61 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
62 cmd->hdr.result = 0;
64 cmd->type = cpu_to_le16(type);
65 cmd->action = cpu_to_le16(action);
67 ret = lbs_cmd_with_response(priv, command, cmd);
69 lbs_deb_leave(LBS_DEB_CMD);
70 return ret;
73 static int lbs_mesh_config_send(struct lbs_private *priv,
74 struct cmd_ds_mesh_config *cmd,
75 uint16_t action, uint16_t type)
77 int ret;
79 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
80 return -EOPNOTSUPP;
82 ret = __lbs_mesh_config_send(priv, cmd, action, type);
83 return ret;
86 /* This function is the CMD_MESH_CONFIG legacy function. It only handles the
87 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
88 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
89 * lbs_mesh_config_send.
91 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
92 uint16_t chan)
94 struct cmd_ds_mesh_config cmd;
95 struct mrvl_meshie *ie;
96 DECLARE_SSID_BUF(ssid);
98 memset(&cmd, 0, sizeof(cmd));
99 cmd.channel = cpu_to_le16(chan);
100 ie = (struct mrvl_meshie *)cmd.data;
102 switch (action) {
103 case CMD_ACT_MESH_CONFIG_START:
104 ie->id = WLAN_EID_VENDOR_SPECIFIC;
105 ie->val.oui[0] = 0x00;
106 ie->val.oui[1] = 0x50;
107 ie->val.oui[2] = 0x43;
108 ie->val.type = MARVELL_MESH_IE_TYPE;
109 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
110 ie->val.version = MARVELL_MESH_IE_VERSION;
111 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
112 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
113 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
114 ie->val.mesh_id_len = priv->mesh_ssid_len;
115 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
116 ie->len = sizeof(struct mrvl_meshie_val) -
117 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
118 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
119 break;
120 case CMD_ACT_MESH_CONFIG_STOP:
121 break;
122 default:
123 return -1;
125 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
126 action, priv->mesh_tlv, chan,
127 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
129 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
132 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
134 priv->mesh_channel = channel;
135 return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
138 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
140 return priv->mesh_channel ?: 1;
143 /***************************************************************************
144 * Mesh sysfs support
148 * Attributes exported through sysfs
152 * lbs_anycast_get - Get function for sysfs attribute anycast_mask
153 * @dev: the &struct device
154 * @attr: device attributes
155 * @buf: buffer where data will be returned
157 static ssize_t lbs_anycast_get(struct device *dev,
158 struct device_attribute *attr, char * buf)
160 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
161 struct cmd_ds_mesh_access mesh_access;
162 int ret;
164 memset(&mesh_access, 0, sizeof(mesh_access));
166 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
167 if (ret)
168 return ret;
170 return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
174 * lbs_anycast_set - Set function for sysfs attribute anycast_mask
175 * @dev: the &struct device
176 * @attr: device attributes
177 * @buf: buffer that contains new attribute value
178 * @count: size of buffer
180 static ssize_t lbs_anycast_set(struct device *dev,
181 struct device_attribute *attr, const char * buf, size_t count)
183 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
184 struct cmd_ds_mesh_access mesh_access;
185 uint32_t datum;
186 int ret;
188 memset(&mesh_access, 0, sizeof(mesh_access));
189 sscanf(buf, "%x", &datum);
190 mesh_access.data[0] = cpu_to_le32(datum);
192 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
193 if (ret)
194 return ret;
196 return strlen(buf);
200 * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
201 * @dev: the &struct device
202 * @attr: device attributes
203 * @buf: buffer where data will be returned
205 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
206 struct device_attribute *attr, char *buf)
208 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
209 struct cmd_ds_mesh_access mesh_access;
210 int ret;
211 u32 retry_limit;
213 memset(&mesh_access, 0, sizeof(mesh_access));
214 mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
216 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
217 &mesh_access);
218 if (ret)
219 return ret;
221 retry_limit = le32_to_cpu(mesh_access.data[1]);
222 return snprintf(buf, 10, "%d\n", retry_limit);
226 * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
227 * @dev: the &struct device
228 * @attr: device attributes
229 * @buf: buffer that contains new attribute value
230 * @count: size of buffer
232 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
233 struct device_attribute *attr, const char *buf, size_t count)
235 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
236 struct cmd_ds_mesh_access mesh_access;
237 int ret;
238 unsigned long retry_limit;
240 memset(&mesh_access, 0, sizeof(mesh_access));
241 mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
243 if (!kstrtoul(buf, 10, &retry_limit))
244 return -ENOTSUPP;
245 if (retry_limit > 15)
246 return -ENOTSUPP;
248 mesh_access.data[1] = cpu_to_le32(retry_limit);
250 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
251 &mesh_access);
252 if (ret)
253 return ret;
255 return strlen(buf);
259 * lbs_mesh_get - Get function for sysfs attribute mesh
260 * @dev: the &struct device
261 * @attr: device attributes
262 * @buf: buffer where data will be returned
264 static ssize_t lbs_mesh_get(struct device *dev,
265 struct device_attribute *attr, char * buf)
267 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
268 return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
272 * lbs_mesh_set - Set function for sysfs attribute mesh
273 * @dev: the &struct device
274 * @attr: device attributes
275 * @buf: buffer that contains new attribute value
276 * @count: size of buffer
278 static ssize_t lbs_mesh_set(struct device *dev,
279 struct device_attribute *attr, const char * buf, size_t count)
281 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
282 int enable;
284 sscanf(buf, "%x", &enable);
285 enable = !!enable;
286 if (enable == !!priv->mesh_dev)
287 return count;
289 if (enable)
290 lbs_add_mesh(priv);
291 else
292 lbs_remove_mesh(priv);
294 return count;
298 * lbs_mesh attribute to be exported per ethX interface
299 * through sysfs (/sys/class/net/ethX/lbs_mesh)
301 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
304 * anycast_mask attribute to be exported per mshX interface
305 * through sysfs (/sys/class/net/mshX/anycast_mask)
307 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
310 * prb_rsp_limit attribute to be exported per mshX interface
311 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
313 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
314 lbs_prb_rsp_limit_set);
316 static struct attribute *lbs_mesh_sysfs_entries[] = {
317 &dev_attr_anycast_mask.attr,
318 &dev_attr_prb_rsp_limit.attr,
319 NULL,
322 static const struct attribute_group lbs_mesh_attr_group = {
323 .attrs = lbs_mesh_sysfs_entries,
327 /***************************************************************************
328 * Persistent configuration support
331 static int mesh_get_default_parameters(struct device *dev,
332 struct mrvl_mesh_defaults *defs)
334 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
335 struct cmd_ds_mesh_config cmd;
336 int ret;
338 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
339 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
340 CMD_TYPE_MESH_GET_DEFAULTS);
342 if (ret)
343 return -EOPNOTSUPP;
345 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
347 return 0;
351 * bootflag_get - Get function for sysfs attribute bootflag
352 * @dev: the &struct device
353 * @attr: device attributes
354 * @buf: buffer where data will be returned
356 static ssize_t bootflag_get(struct device *dev,
357 struct device_attribute *attr, char *buf)
359 struct mrvl_mesh_defaults defs;
360 int ret;
362 ret = mesh_get_default_parameters(dev, &defs);
364 if (ret)
365 return ret;
367 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
371 * bootflag_set - Set function for sysfs attribute bootflag
372 * @dev: the &struct device
373 * @attr: device attributes
374 * @buf: buffer that contains new attribute value
375 * @count: size of buffer
377 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
378 const char *buf, size_t count)
380 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
381 struct cmd_ds_mesh_config cmd;
382 uint32_t datum;
383 int ret;
385 memset(&cmd, 0, sizeof(cmd));
386 ret = sscanf(buf, "%d", &datum);
387 if ((ret != 1) || (datum > 1))
388 return -EINVAL;
390 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
391 cmd.length = cpu_to_le16(sizeof(uint32_t));
392 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
393 CMD_TYPE_MESH_SET_BOOTFLAG);
394 if (ret)
395 return ret;
397 return strlen(buf);
401 * boottime_get - Get function for sysfs attribute boottime
402 * @dev: the &struct device
403 * @attr: device attributes
404 * @buf: buffer where data will be returned
406 static ssize_t boottime_get(struct device *dev,
407 struct device_attribute *attr, char *buf)
409 struct mrvl_mesh_defaults defs;
410 int ret;
412 ret = mesh_get_default_parameters(dev, &defs);
414 if (ret)
415 return ret;
417 return snprintf(buf, 12, "%d\n", defs.boottime);
421 * boottime_set - Set function for sysfs attribute boottime
422 * @dev: the &struct device
423 * @attr: device attributes
424 * @buf: buffer that contains new attribute value
425 * @count: size of buffer
427 static ssize_t boottime_set(struct device *dev,
428 struct device_attribute *attr, const char *buf, size_t count)
430 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
431 struct cmd_ds_mesh_config cmd;
432 uint32_t datum;
433 int ret;
435 memset(&cmd, 0, sizeof(cmd));
436 ret = sscanf(buf, "%d", &datum);
437 if ((ret != 1) || (datum > 255))
438 return -EINVAL;
440 /* A too small boot time will result in the device booting into
441 * standalone (no-host) mode before the host can take control of it,
442 * so the change will be hard to revert. This may be a desired
443 * feature (e.g to configure a very fast boot time for devices that
444 * will not be attached to a host), but dangerous. So I'm enforcing a
445 * lower limit of 20 seconds: remove and recompile the driver if this
446 * does not work for you.
448 datum = (datum < 20) ? 20 : datum;
449 cmd.data[0] = datum;
450 cmd.length = cpu_to_le16(sizeof(uint8_t));
451 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
452 CMD_TYPE_MESH_SET_BOOTTIME);
453 if (ret)
454 return ret;
456 return strlen(buf);
460 * channel_get - Get function for sysfs attribute channel
461 * @dev: the &struct device
462 * @attr: device attributes
463 * @buf: buffer where data will be returned
465 static ssize_t channel_get(struct device *dev,
466 struct device_attribute *attr, char *buf)
468 struct mrvl_mesh_defaults defs;
469 int ret;
471 ret = mesh_get_default_parameters(dev, &defs);
473 if (ret)
474 return ret;
476 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
480 * channel_set - Set function for sysfs attribute channel
481 * @dev: the &struct device
482 * @attr: device attributes
483 * @buf: buffer that contains new attribute value
484 * @count: size of buffer
486 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
487 const char *buf, size_t count)
489 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
490 struct cmd_ds_mesh_config cmd;
491 uint32_t datum;
492 int ret;
494 memset(&cmd, 0, sizeof(cmd));
495 ret = sscanf(buf, "%d", &datum);
496 if (ret != 1 || datum < 1 || datum > 11)
497 return -EINVAL;
499 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
500 cmd.length = cpu_to_le16(sizeof(uint16_t));
501 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
502 CMD_TYPE_MESH_SET_DEF_CHANNEL);
503 if (ret)
504 return ret;
506 return strlen(buf);
510 * mesh_id_get - Get function for sysfs attribute mesh_id
511 * @dev: the &struct device
512 * @attr: device attributes
513 * @buf: buffer where data will be returned
515 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
516 char *buf)
518 struct mrvl_mesh_defaults defs;
519 int ret;
521 ret = mesh_get_default_parameters(dev, &defs);
523 if (ret)
524 return ret;
526 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
527 dev_err(dev, "inconsistent mesh ID length\n");
528 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
531 memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
532 buf[defs.meshie.val.mesh_id_len] = '\n';
533 buf[defs.meshie.val.mesh_id_len + 1] = '\0';
535 return defs.meshie.val.mesh_id_len + 1;
539 * mesh_id_set - Set function for sysfs attribute mesh_id
540 * @dev: the &struct device
541 * @attr: device attributes
542 * @buf: buffer that contains new attribute value
543 * @count: size of buffer
545 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
546 const char *buf, size_t count)
548 struct cmd_ds_mesh_config cmd;
549 struct mrvl_mesh_defaults defs;
550 struct mrvl_meshie *ie;
551 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
552 int len;
553 int ret;
555 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
556 return -EINVAL;
558 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
559 ie = (struct mrvl_meshie *) &cmd.data[0];
561 /* fetch all other Information Element parameters */
562 ret = mesh_get_default_parameters(dev, &defs);
564 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
566 /* transfer IE elements */
567 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
569 len = count - 1;
570 memcpy(ie->val.mesh_id, buf, len);
571 /* SSID len */
572 ie->val.mesh_id_len = len;
573 /* IE len */
574 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
576 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
577 CMD_TYPE_MESH_SET_MESH_IE);
578 if (ret)
579 return ret;
581 return strlen(buf);
585 * protocol_id_get - Get function for sysfs attribute protocol_id
586 * @dev: the &struct device
587 * @attr: device attributes
588 * @buf: buffer where data will be returned
590 static ssize_t protocol_id_get(struct device *dev,
591 struct device_attribute *attr, char *buf)
593 struct mrvl_mesh_defaults defs;
594 int ret;
596 ret = mesh_get_default_parameters(dev, &defs);
598 if (ret)
599 return ret;
601 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
605 * protocol_id_set - Set function for sysfs attribute protocol_id
606 * @dev: the &struct device
607 * @attr: device attributes
608 * @buf: buffer that contains new attribute value
609 * @count: size of buffer
611 static ssize_t protocol_id_set(struct device *dev,
612 struct device_attribute *attr, const char *buf, size_t count)
614 struct cmd_ds_mesh_config cmd;
615 struct mrvl_mesh_defaults defs;
616 struct mrvl_meshie *ie;
617 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
618 uint32_t datum;
619 int ret;
621 memset(&cmd, 0, sizeof(cmd));
622 ret = sscanf(buf, "%d", &datum);
623 if ((ret != 1) || (datum > 255))
624 return -EINVAL;
626 /* fetch all other Information Element parameters */
627 ret = mesh_get_default_parameters(dev, &defs);
629 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
631 /* transfer IE elements */
632 ie = (struct mrvl_meshie *) &cmd.data[0];
633 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
634 /* update protocol id */
635 ie->val.active_protocol_id = datum;
637 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
638 CMD_TYPE_MESH_SET_MESH_IE);
639 if (ret)
640 return ret;
642 return strlen(buf);
646 * metric_id_get - Get function for sysfs attribute metric_id
647 * @dev: the &struct device
648 * @attr: device attributes
649 * @buf: buffer where data will be returned
651 static ssize_t metric_id_get(struct device *dev,
652 struct device_attribute *attr, char *buf)
654 struct mrvl_mesh_defaults defs;
655 int ret;
657 ret = mesh_get_default_parameters(dev, &defs);
659 if (ret)
660 return ret;
662 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
666 * metric_id_set - Set function for sysfs attribute metric_id
667 * @dev: the &struct device
668 * @attr: device attributes
669 * @buf: buffer that contains new attribute value
670 * @count: size of buffer
672 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
673 const char *buf, size_t count)
675 struct cmd_ds_mesh_config cmd;
676 struct mrvl_mesh_defaults defs;
677 struct mrvl_meshie *ie;
678 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
679 uint32_t datum;
680 int ret;
682 memset(&cmd, 0, sizeof(cmd));
683 ret = sscanf(buf, "%d", &datum);
684 if ((ret != 1) || (datum > 255))
685 return -EINVAL;
687 /* fetch all other Information Element parameters */
688 ret = mesh_get_default_parameters(dev, &defs);
690 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
692 /* transfer IE elements */
693 ie = (struct mrvl_meshie *) &cmd.data[0];
694 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
695 /* update metric id */
696 ie->val.active_metric_id = datum;
698 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
699 CMD_TYPE_MESH_SET_MESH_IE);
700 if (ret)
701 return ret;
703 return strlen(buf);
707 * capability_get - Get function for sysfs attribute capability
708 * @dev: the &struct device
709 * @attr: device attributes
710 * @buf: buffer where data will be returned
712 static ssize_t capability_get(struct device *dev,
713 struct device_attribute *attr, char *buf)
715 struct mrvl_mesh_defaults defs;
716 int ret;
718 ret = mesh_get_default_parameters(dev, &defs);
720 if (ret)
721 return ret;
723 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
727 * capability_set - Set function for sysfs attribute capability
728 * @dev: the &struct device
729 * @attr: device attributes
730 * @buf: buffer that contains new attribute value
731 * @count: size of buffer
733 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
734 const char *buf, size_t count)
736 struct cmd_ds_mesh_config cmd;
737 struct mrvl_mesh_defaults defs;
738 struct mrvl_meshie *ie;
739 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
740 uint32_t datum;
741 int ret;
743 memset(&cmd, 0, sizeof(cmd));
744 ret = sscanf(buf, "%d", &datum);
745 if ((ret != 1) || (datum > 255))
746 return -EINVAL;
748 /* fetch all other Information Element parameters */
749 ret = mesh_get_default_parameters(dev, &defs);
751 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
753 /* transfer IE elements */
754 ie = (struct mrvl_meshie *) &cmd.data[0];
755 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
756 /* update value */
757 ie->val.mesh_capability = datum;
759 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
760 CMD_TYPE_MESH_SET_MESH_IE);
761 if (ret)
762 return ret;
764 return strlen(buf);
768 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
769 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
770 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
771 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
772 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
773 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
774 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
776 static struct attribute *boot_opts_attrs[] = {
777 &dev_attr_bootflag.attr,
778 &dev_attr_boottime.attr,
779 &dev_attr_channel.attr,
780 NULL
783 static const struct attribute_group boot_opts_group = {
784 .name = "boot_options",
785 .attrs = boot_opts_attrs,
788 static struct attribute *mesh_ie_attrs[] = {
789 &dev_attr_mesh_id.attr,
790 &dev_attr_protocol_id.attr,
791 &dev_attr_metric_id.attr,
792 &dev_attr_capability.attr,
793 NULL
796 static const struct attribute_group mesh_ie_group = {
797 .name = "mesh_ie",
798 .attrs = mesh_ie_attrs,
801 static void lbs_persist_config_init(struct net_device *dev)
803 int ret;
804 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
805 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
808 static void lbs_persist_config_remove(struct net_device *dev)
810 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
811 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
815 /***************************************************************************
816 * Initializing and starting, stopping mesh
820 * Check mesh FW version and appropriately send the mesh start
821 * command
823 int lbs_init_mesh(struct lbs_private *priv)
825 int ret = 0;
827 lbs_deb_enter(LBS_DEB_MESH);
829 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
830 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
831 /* 5.110.22 have mesh command with 0xa3 command id */
832 /* 10.0.0.p0 FW brings in mesh config command with different id */
833 /* Check FW version MSB and initialize mesh_fw_ver */
834 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
835 /* Enable mesh, if supported, and work out which TLV it uses.
836 0x100 + 291 is an unofficial value used in 5.110.20.pXX
837 0x100 + 37 is the official value used in 5.110.21.pXX
838 but we check them in that order because 20.pXX doesn't
839 give an error -- it just silently fails. */
841 /* 5.110.20.pXX firmware will fail the command if the channel
842 doesn't match the existing channel. But only if the TLV
843 is correct. If the channel is wrong, _BOTH_ versions will
844 give an error to 0x100+291, and allow 0x100+37 to succeed.
845 It's just that 5.110.20.pXX will not have done anything
846 useful */
848 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
849 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
850 priv->mesh_tlv = TLV_TYPE_MESH_ID;
851 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
852 priv->mesh_tlv = 0;
854 } else
855 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
856 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
857 /* 10.0.0.pXX new firmwares should succeed with TLV
858 * 0x100+37; Do not invoke command with old TLV.
860 priv->mesh_tlv = TLV_TYPE_MESH_ID;
861 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
862 priv->mesh_tlv = 0;
865 /* Stop meshing until interface is brought up */
866 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
868 if (priv->mesh_tlv) {
869 sprintf(priv->mesh_ssid, "mesh");
870 priv->mesh_ssid_len = 4;
871 ret = 1;
874 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875 return ret;
878 void lbs_start_mesh(struct lbs_private *priv)
880 lbs_add_mesh(priv);
882 if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
883 netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
886 int lbs_deinit_mesh(struct lbs_private *priv)
888 struct net_device *dev = priv->dev;
889 int ret = 0;
891 lbs_deb_enter(LBS_DEB_MESH);
893 if (priv->mesh_tlv) {
894 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
895 ret = 1;
898 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
899 return ret;
904 * lbs_mesh_stop - close the mshX interface
906 * @dev: A pointer to &net_device structure
907 * returns: 0
909 static int lbs_mesh_stop(struct net_device *dev)
911 struct lbs_private *priv = dev->ml_priv;
913 lbs_deb_enter(LBS_DEB_MESH);
914 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
915 lbs_mesh_get_channel(priv));
917 spin_lock_irq(&priv->driver_lock);
919 netif_stop_queue(dev);
920 netif_carrier_off(dev);
922 spin_unlock_irq(&priv->driver_lock);
924 lbs_update_mcast(priv);
925 if (!lbs_iface_active(priv))
926 lbs_stop_iface(priv);
928 lbs_deb_leave(LBS_DEB_MESH);
929 return 0;
933 * lbs_mesh_dev_open - open the mshX interface
935 * @dev: A pointer to &net_device structure
936 * returns: 0 or -EBUSY if monitor mode active
938 static int lbs_mesh_dev_open(struct net_device *dev)
940 struct lbs_private *priv = dev->ml_priv;
941 int ret = 0;
943 lbs_deb_enter(LBS_DEB_NET);
944 if (!priv->iface_running) {
945 ret = lbs_start_iface(priv);
946 if (ret)
947 goto out;
950 spin_lock_irq(&priv->driver_lock);
952 if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
953 ret = -EBUSY;
954 spin_unlock_irq(&priv->driver_lock);
955 goto out;
958 netif_carrier_on(dev);
960 if (!priv->tx_pending_len)
961 netif_wake_queue(dev);
963 spin_unlock_irq(&priv->driver_lock);
965 ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
966 lbs_mesh_get_channel(priv));
968 out:
969 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
970 return ret;
973 static const struct net_device_ops mesh_netdev_ops = {
974 .ndo_open = lbs_mesh_dev_open,
975 .ndo_stop = lbs_mesh_stop,
976 .ndo_start_xmit = lbs_hard_start_xmit,
977 .ndo_set_mac_address = lbs_set_mac_address,
978 .ndo_set_rx_mode = lbs_set_multicast_list,
982 * lbs_add_mesh - add mshX interface
984 * @priv: A pointer to the &struct lbs_private structure
985 * returns: 0 if successful, -X otherwise
987 static int lbs_add_mesh(struct lbs_private *priv)
989 struct net_device *mesh_dev = NULL;
990 struct wireless_dev *mesh_wdev;
991 int ret = 0;
993 lbs_deb_enter(LBS_DEB_MESH);
995 /* Allocate a virtual mesh device */
996 mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
997 if (!mesh_wdev) {
998 lbs_deb_mesh("init mshX wireless device failed\n");
999 ret = -ENOMEM;
1000 goto done;
1003 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
1004 if (!mesh_dev) {
1005 lbs_deb_mesh("init mshX device failed\n");
1006 ret = -ENOMEM;
1007 goto err_free_wdev;
1010 mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
1011 mesh_wdev->wiphy = priv->wdev->wiphy;
1012 mesh_wdev->netdev = mesh_dev;
1014 mesh_dev->ml_priv = priv;
1015 mesh_dev->ieee80211_ptr = mesh_wdev;
1016 priv->mesh_dev = mesh_dev;
1018 mesh_dev->netdev_ops = &mesh_netdev_ops;
1019 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1020 eth_hw_addr_inherit(mesh_dev, priv->dev);
1022 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1024 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1025 /* Register virtual mesh interface */
1026 ret = register_netdev(mesh_dev);
1027 if (ret) {
1028 pr_err("cannot register mshX virtual interface\n");
1029 goto err_free_netdev;
1032 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1033 if (ret)
1034 goto err_unregister;
1036 lbs_persist_config_init(mesh_dev);
1038 /* Everything successful */
1039 ret = 0;
1040 goto done;
1042 err_unregister:
1043 unregister_netdev(mesh_dev);
1045 err_free_netdev:
1046 free_netdev(mesh_dev);
1048 err_free_wdev:
1049 kfree(mesh_wdev);
1051 done:
1052 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1053 return ret;
1056 void lbs_remove_mesh(struct lbs_private *priv)
1058 struct net_device *mesh_dev;
1060 mesh_dev = priv->mesh_dev;
1061 if (!mesh_dev)
1062 return;
1064 lbs_deb_enter(LBS_DEB_MESH);
1065 netif_stop_queue(mesh_dev);
1066 netif_carrier_off(mesh_dev);
1067 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1068 lbs_persist_config_remove(mesh_dev);
1069 unregister_netdev(mesh_dev);
1070 priv->mesh_dev = NULL;
1071 kfree(mesh_dev->ieee80211_ptr);
1072 free_netdev(mesh_dev);
1073 lbs_deb_leave(LBS_DEB_MESH);
1077 /***************************************************************************
1078 * Sending and receiving
1080 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1081 struct net_device *dev, struct rxpd *rxpd)
1083 if (priv->mesh_dev) {
1084 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1085 if (rxpd->rx_control & RxPD_MESH_FRAME)
1086 dev = priv->mesh_dev;
1087 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1088 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1089 dev = priv->mesh_dev;
1092 return dev;
1096 void lbs_mesh_set_txpd(struct lbs_private *priv,
1097 struct net_device *dev, struct txpd *txpd)
1099 if (dev == priv->mesh_dev) {
1100 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1101 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1102 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1103 txpd->u.bss.bss_num = MESH_IFACE_ID;
1108 /***************************************************************************
1109 * Ethtool related
1112 static const char * const mesh_stat_strings[] = {
1113 "drop_duplicate_bcast",
1114 "drop_ttl_zero",
1115 "drop_no_fwd_route",
1116 "drop_no_buffers",
1117 "fwded_unicast_cnt",
1118 "fwded_bcast_cnt",
1119 "drop_blind_table",
1120 "tx_failed_cnt"
1123 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1124 struct ethtool_stats *stats, uint64_t *data)
1126 struct lbs_private *priv = dev->ml_priv;
1127 struct cmd_ds_mesh_access mesh_access;
1128 int ret;
1130 lbs_deb_enter(LBS_DEB_ETHTOOL);
1132 /* Get Mesh Statistics */
1133 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1135 if (ret) {
1136 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1137 return;
1140 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1141 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1142 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1143 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1144 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1145 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1146 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1147 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1149 data[0] = priv->mstats.fwd_drop_rbt;
1150 data[1] = priv->mstats.fwd_drop_ttl;
1151 data[2] = priv->mstats.fwd_drop_noroute;
1152 data[3] = priv->mstats.fwd_drop_nobuf;
1153 data[4] = priv->mstats.fwd_unicast_cnt;
1154 data[5] = priv->mstats.fwd_bcast_cnt;
1155 data[6] = priv->mstats.drop_blind;
1156 data[7] = priv->mstats.tx_failed_cnt;
1158 lbs_deb_enter(LBS_DEB_ETHTOOL);
1161 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1163 struct lbs_private *priv = dev->ml_priv;
1165 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1166 return MESH_STATS_NUM;
1168 return -EOPNOTSUPP;
1171 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1172 uint32_t stringset, uint8_t *s)
1174 int i;
1176 lbs_deb_enter(LBS_DEB_ETHTOOL);
1178 switch (stringset) {
1179 case ETH_SS_STATS:
1180 for (i = 0; i < MESH_STATS_NUM; i++) {
1181 memcpy(s + i * ETH_GSTRING_LEN,
1182 mesh_stat_strings[i],
1183 ETH_GSTRING_LEN);
1185 break;
1187 lbs_deb_enter(LBS_DEB_ETHTOOL);