include: replace linux/module.h with "struct module" wherever possible
[linux-2.6/next.git] / drivers / net / wireless / libertas / mesh.c
blobbe72c08ea2a79acf457c4ef3e5e7b82ae927cbfc
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_GENERIC;
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);
133 /***************************************************************************
134 * Mesh sysfs support
138 * Attributes exported through sysfs
142 * lbs_anycast_get - Get function for sysfs attribute anycast_mask
143 * @dev: the &struct device
144 * @attr: device attributes
145 * @buf: buffer where data will be returned
147 static ssize_t lbs_anycast_get(struct device *dev,
148 struct device_attribute *attr, char * buf)
150 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
151 struct cmd_ds_mesh_access mesh_access;
152 int ret;
154 memset(&mesh_access, 0, sizeof(mesh_access));
156 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
157 if (ret)
158 return ret;
160 return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
164 * lbs_anycast_set - Set function for sysfs attribute anycast_mask
165 * @dev: the &struct device
166 * @attr: device attributes
167 * @buf: buffer that contains new attribute value
168 * @count: size of buffer
170 static ssize_t lbs_anycast_set(struct device *dev,
171 struct device_attribute *attr, const char * buf, size_t count)
173 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
174 struct cmd_ds_mesh_access mesh_access;
175 uint32_t datum;
176 int ret;
178 memset(&mesh_access, 0, sizeof(mesh_access));
179 sscanf(buf, "%x", &datum);
180 mesh_access.data[0] = cpu_to_le32(datum);
182 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
183 if (ret)
184 return ret;
186 return strlen(buf);
190 * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
191 * @dev: the &struct device
192 * @attr: device attributes
193 * @buf: buffer where data will be returned
195 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
196 struct device_attribute *attr, char *buf)
198 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
199 struct cmd_ds_mesh_access mesh_access;
200 int ret;
201 u32 retry_limit;
203 memset(&mesh_access, 0, sizeof(mesh_access));
204 mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
206 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
207 &mesh_access);
208 if (ret)
209 return ret;
211 retry_limit = le32_to_cpu(mesh_access.data[1]);
212 return snprintf(buf, 10, "%d\n", retry_limit);
216 * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
217 * @dev: the &struct device
218 * @attr: device attributes
219 * @buf: buffer that contains new attribute value
220 * @count: size of buffer
222 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
223 struct device_attribute *attr, const char *buf, size_t count)
225 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
226 struct cmd_ds_mesh_access mesh_access;
227 int ret;
228 unsigned long retry_limit;
230 memset(&mesh_access, 0, sizeof(mesh_access));
231 mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
233 if (!strict_strtoul(buf, 10, &retry_limit))
234 return -ENOTSUPP;
235 if (retry_limit > 15)
236 return -ENOTSUPP;
238 mesh_access.data[1] = cpu_to_le32(retry_limit);
240 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
241 &mesh_access);
242 if (ret)
243 return ret;
245 return strlen(buf);
249 * lbs_mesh_get - Get function for sysfs attribute mesh
250 * @dev: the &struct device
251 * @attr: device attributes
252 * @buf: buffer where data will be returned
254 static ssize_t lbs_mesh_get(struct device *dev,
255 struct device_attribute *attr, char * buf)
257 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
258 return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
262 * lbs_mesh_set - Set function for sysfs attribute mesh
263 * @dev: the &struct device
264 * @attr: device attributes
265 * @buf: buffer that contains new attribute value
266 * @count: size of buffer
268 static ssize_t lbs_mesh_set(struct device *dev,
269 struct device_attribute *attr, const char * buf, size_t count)
271 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
272 int enable;
274 sscanf(buf, "%x", &enable);
275 enable = !!enable;
276 if (enable == !!priv->mesh_dev)
277 return count;
279 if (enable)
280 lbs_add_mesh(priv);
281 else
282 lbs_remove_mesh(priv);
284 return count;
288 * lbs_mesh attribute to be exported per ethX interface
289 * through sysfs (/sys/class/net/ethX/lbs_mesh)
291 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
294 * anycast_mask attribute to be exported per mshX interface
295 * through sysfs (/sys/class/net/mshX/anycast_mask)
297 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
300 * prb_rsp_limit attribute to be exported per mshX interface
301 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
303 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
304 lbs_prb_rsp_limit_set);
306 static struct attribute *lbs_mesh_sysfs_entries[] = {
307 &dev_attr_anycast_mask.attr,
308 &dev_attr_prb_rsp_limit.attr,
309 NULL,
312 static const struct attribute_group lbs_mesh_attr_group = {
313 .attrs = lbs_mesh_sysfs_entries,
317 /***************************************************************************
318 * Persistent configuration support
321 static int mesh_get_default_parameters(struct device *dev,
322 struct mrvl_mesh_defaults *defs)
324 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
325 struct cmd_ds_mesh_config cmd;
326 int ret;
328 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
329 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
330 CMD_TYPE_MESH_GET_DEFAULTS);
332 if (ret)
333 return -EOPNOTSUPP;
335 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
337 return 0;
341 * bootflag_get - Get function for sysfs attribute bootflag
342 * @dev: the &struct device
343 * @attr: device attributes
344 * @buf: buffer where data will be returned
346 static ssize_t bootflag_get(struct device *dev,
347 struct device_attribute *attr, char *buf)
349 struct mrvl_mesh_defaults defs;
350 int ret;
352 ret = mesh_get_default_parameters(dev, &defs);
354 if (ret)
355 return ret;
357 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
361 * bootflag_set - Set function for sysfs attribute bootflag
362 * @dev: the &struct device
363 * @attr: device attributes
364 * @buf: buffer that contains new attribute value
365 * @count: size of buffer
367 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
368 const char *buf, size_t count)
370 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
371 struct cmd_ds_mesh_config cmd;
372 uint32_t datum;
373 int ret;
375 memset(&cmd, 0, sizeof(cmd));
376 ret = sscanf(buf, "%d", &datum);
377 if ((ret != 1) || (datum > 1))
378 return -EINVAL;
380 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
381 cmd.length = cpu_to_le16(sizeof(uint32_t));
382 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
383 CMD_TYPE_MESH_SET_BOOTFLAG);
384 if (ret)
385 return ret;
387 return strlen(buf);
391 * boottime_get - Get function for sysfs attribute boottime
392 * @dev: the &struct device
393 * @attr: device attributes
394 * @buf: buffer where data will be returned
396 static ssize_t boottime_get(struct device *dev,
397 struct device_attribute *attr, char *buf)
399 struct mrvl_mesh_defaults defs;
400 int ret;
402 ret = mesh_get_default_parameters(dev, &defs);
404 if (ret)
405 return ret;
407 return snprintf(buf, 12, "%d\n", defs.boottime);
411 * boottime_set - Set function for sysfs attribute boottime
412 * @dev: the &struct device
413 * @attr: device attributes
414 * @buf: buffer that contains new attribute value
415 * @count: size of buffer
417 static ssize_t boottime_set(struct device *dev,
418 struct device_attribute *attr, const char *buf, size_t count)
420 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
421 struct cmd_ds_mesh_config cmd;
422 uint32_t datum;
423 int ret;
425 memset(&cmd, 0, sizeof(cmd));
426 ret = sscanf(buf, "%d", &datum);
427 if ((ret != 1) || (datum > 255))
428 return -EINVAL;
430 /* A too small boot time will result in the device booting into
431 * standalone (no-host) mode before the host can take control of it,
432 * so the change will be hard to revert. This may be a desired
433 * feature (e.g to configure a very fast boot time for devices that
434 * will not be attached to a host), but dangerous. So I'm enforcing a
435 * lower limit of 20 seconds: remove and recompile the driver if this
436 * does not work for you.
438 datum = (datum < 20) ? 20 : datum;
439 cmd.data[0] = datum;
440 cmd.length = cpu_to_le16(sizeof(uint8_t));
441 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
442 CMD_TYPE_MESH_SET_BOOTTIME);
443 if (ret)
444 return ret;
446 return strlen(buf);
450 * channel_get - Get function for sysfs attribute channel
451 * @dev: the &struct device
452 * @attr: device attributes
453 * @buf: buffer where data will be returned
455 static ssize_t channel_get(struct device *dev,
456 struct device_attribute *attr, char *buf)
458 struct mrvl_mesh_defaults defs;
459 int ret;
461 ret = mesh_get_default_parameters(dev, &defs);
463 if (ret)
464 return ret;
466 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
470 * channel_set - Set function for sysfs attribute channel
471 * @dev: the &struct device
472 * @attr: device attributes
473 * @buf: buffer that contains new attribute value
474 * @count: size of buffer
476 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
477 const char *buf, size_t count)
479 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
480 struct cmd_ds_mesh_config cmd;
481 uint32_t datum;
482 int ret;
484 memset(&cmd, 0, sizeof(cmd));
485 ret = sscanf(buf, "%d", &datum);
486 if (ret != 1 || datum < 1 || datum > 11)
487 return -EINVAL;
489 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
490 cmd.length = cpu_to_le16(sizeof(uint16_t));
491 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
492 CMD_TYPE_MESH_SET_DEF_CHANNEL);
493 if (ret)
494 return ret;
496 return strlen(buf);
500 * mesh_id_get - Get function for sysfs attribute mesh_id
501 * @dev: the &struct device
502 * @attr: device attributes
503 * @buf: buffer where data will be returned
505 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
506 char *buf)
508 struct mrvl_mesh_defaults defs;
509 int ret;
511 ret = mesh_get_default_parameters(dev, &defs);
513 if (ret)
514 return ret;
516 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
517 dev_err(dev, "inconsistent mesh ID length\n");
518 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
521 memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
522 buf[defs.meshie.val.mesh_id_len] = '\n';
523 buf[defs.meshie.val.mesh_id_len + 1] = '\0';
525 return defs.meshie.val.mesh_id_len + 1;
529 * mesh_id_set - Set function for sysfs attribute mesh_id
530 * @dev: the &struct device
531 * @attr: device attributes
532 * @buf: buffer that contains new attribute value
533 * @count: size of buffer
535 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
536 const char *buf, size_t count)
538 struct cmd_ds_mesh_config cmd;
539 struct mrvl_mesh_defaults defs;
540 struct mrvl_meshie *ie;
541 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
542 int len;
543 int ret;
545 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
546 return -EINVAL;
548 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
549 ie = (struct mrvl_meshie *) &cmd.data[0];
551 /* fetch all other Information Element parameters */
552 ret = mesh_get_default_parameters(dev, &defs);
554 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
556 /* transfer IE elements */
557 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
559 len = count - 1;
560 memcpy(ie->val.mesh_id, buf, len);
561 /* SSID len */
562 ie->val.mesh_id_len = len;
563 /* IE len */
564 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
566 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
567 CMD_TYPE_MESH_SET_MESH_IE);
568 if (ret)
569 return ret;
571 return strlen(buf);
575 * protocol_id_get - Get function for sysfs attribute protocol_id
576 * @dev: the &struct device
577 * @attr: device attributes
578 * @buf: buffer where data will be returned
580 static ssize_t protocol_id_get(struct device *dev,
581 struct device_attribute *attr, char *buf)
583 struct mrvl_mesh_defaults defs;
584 int ret;
586 ret = mesh_get_default_parameters(dev, &defs);
588 if (ret)
589 return ret;
591 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
595 * protocol_id_set - Set function for sysfs attribute protocol_id
596 * @dev: the &struct device
597 * @attr: device attributes
598 * @buf: buffer that contains new attribute value
599 * @count: size of buffer
601 static ssize_t protocol_id_set(struct device *dev,
602 struct device_attribute *attr, const char *buf, size_t count)
604 struct cmd_ds_mesh_config cmd;
605 struct mrvl_mesh_defaults defs;
606 struct mrvl_meshie *ie;
607 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
608 uint32_t datum;
609 int ret;
611 memset(&cmd, 0, sizeof(cmd));
612 ret = sscanf(buf, "%d", &datum);
613 if ((ret != 1) || (datum > 255))
614 return -EINVAL;
616 /* fetch all other Information Element parameters */
617 ret = mesh_get_default_parameters(dev, &defs);
619 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
621 /* transfer IE elements */
622 ie = (struct mrvl_meshie *) &cmd.data[0];
623 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
624 /* update protocol id */
625 ie->val.active_protocol_id = datum;
627 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
628 CMD_TYPE_MESH_SET_MESH_IE);
629 if (ret)
630 return ret;
632 return strlen(buf);
636 * metric_id_get - Get function for sysfs attribute metric_id
637 * @dev: the &struct device
638 * @attr: device attributes
639 * @buf: buffer where data will be returned
641 static ssize_t metric_id_get(struct device *dev,
642 struct device_attribute *attr, char *buf)
644 struct mrvl_mesh_defaults defs;
645 int ret;
647 ret = mesh_get_default_parameters(dev, &defs);
649 if (ret)
650 return ret;
652 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
656 * metric_id_set - Set function for sysfs attribute metric_id
657 * @dev: the &struct device
658 * @attr: device attributes
659 * @buf: buffer that contains new attribute value
660 * @count: size of buffer
662 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
663 const char *buf, size_t count)
665 struct cmd_ds_mesh_config cmd;
666 struct mrvl_mesh_defaults defs;
667 struct mrvl_meshie *ie;
668 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
669 uint32_t datum;
670 int ret;
672 memset(&cmd, 0, sizeof(cmd));
673 ret = sscanf(buf, "%d", &datum);
674 if ((ret != 1) || (datum > 255))
675 return -EINVAL;
677 /* fetch all other Information Element parameters */
678 ret = mesh_get_default_parameters(dev, &defs);
680 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
682 /* transfer IE elements */
683 ie = (struct mrvl_meshie *) &cmd.data[0];
684 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
685 /* update metric id */
686 ie->val.active_metric_id = datum;
688 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
689 CMD_TYPE_MESH_SET_MESH_IE);
690 if (ret)
691 return ret;
693 return strlen(buf);
697 * capability_get - Get function for sysfs attribute capability
698 * @dev: the &struct device
699 * @attr: device attributes
700 * @buf: buffer where data will be returned
702 static ssize_t capability_get(struct device *dev,
703 struct device_attribute *attr, char *buf)
705 struct mrvl_mesh_defaults defs;
706 int ret;
708 ret = mesh_get_default_parameters(dev, &defs);
710 if (ret)
711 return ret;
713 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
717 * capability_set - Set function for sysfs attribute capability
718 * @dev: the &struct device
719 * @attr: device attributes
720 * @buf: buffer that contains new attribute value
721 * @count: size of buffer
723 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
724 const char *buf, size_t count)
726 struct cmd_ds_mesh_config cmd;
727 struct mrvl_mesh_defaults defs;
728 struct mrvl_meshie *ie;
729 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
730 uint32_t datum;
731 int ret;
733 memset(&cmd, 0, sizeof(cmd));
734 ret = sscanf(buf, "%d", &datum);
735 if ((ret != 1) || (datum > 255))
736 return -EINVAL;
738 /* fetch all other Information Element parameters */
739 ret = mesh_get_default_parameters(dev, &defs);
741 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
743 /* transfer IE elements */
744 ie = (struct mrvl_meshie *) &cmd.data[0];
745 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
746 /* update value */
747 ie->val.mesh_capability = datum;
749 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
750 CMD_TYPE_MESH_SET_MESH_IE);
751 if (ret)
752 return ret;
754 return strlen(buf);
758 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
759 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
760 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
761 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
762 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
763 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
764 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
766 static struct attribute *boot_opts_attrs[] = {
767 &dev_attr_bootflag.attr,
768 &dev_attr_boottime.attr,
769 &dev_attr_channel.attr,
770 NULL
773 static const struct attribute_group boot_opts_group = {
774 .name = "boot_options",
775 .attrs = boot_opts_attrs,
778 static struct attribute *mesh_ie_attrs[] = {
779 &dev_attr_mesh_id.attr,
780 &dev_attr_protocol_id.attr,
781 &dev_attr_metric_id.attr,
782 &dev_attr_capability.attr,
783 NULL
786 static const struct attribute_group mesh_ie_group = {
787 .name = "mesh_ie",
788 .attrs = mesh_ie_attrs,
791 static void lbs_persist_config_init(struct net_device *dev)
793 int ret;
794 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
795 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
798 static void lbs_persist_config_remove(struct net_device *dev)
800 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
801 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
805 /***************************************************************************
806 * Initializing and starting, stopping mesh
810 * Check mesh FW version and appropriately send the mesh start
811 * command
813 int lbs_init_mesh(struct lbs_private *priv)
815 struct net_device *dev = priv->dev;
816 int ret = 0;
818 lbs_deb_enter(LBS_DEB_MESH);
820 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
821 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
822 /* 5.110.22 have mesh command with 0xa3 command id */
823 /* 10.0.0.p0 FW brings in mesh config command with different id */
824 /* Check FW version MSB and initialize mesh_fw_ver */
825 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
826 /* Enable mesh, if supported, and work out which TLV it uses.
827 0x100 + 291 is an unofficial value used in 5.110.20.pXX
828 0x100 + 37 is the official value used in 5.110.21.pXX
829 but we check them in that order because 20.pXX doesn't
830 give an error -- it just silently fails. */
832 /* 5.110.20.pXX firmware will fail the command if the channel
833 doesn't match the existing channel. But only if the TLV
834 is correct. If the channel is wrong, _BOTH_ versions will
835 give an error to 0x100+291, and allow 0x100+37 to succeed.
836 It's just that 5.110.20.pXX will not have done anything
837 useful */
839 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
840 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
841 priv->channel)) {
842 priv->mesh_tlv = TLV_TYPE_MESH_ID;
843 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
844 priv->channel))
845 priv->mesh_tlv = 0;
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.
853 priv->mesh_tlv = TLV_TYPE_MESH_ID;
854 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
855 priv->channel))
856 priv->mesh_tlv = 0;
859 /* Stop meshing until interface is brought up */
860 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
862 if (priv->mesh_tlv) {
863 sprintf(priv->mesh_ssid, "mesh");
864 priv->mesh_ssid_len = 4;
866 lbs_add_mesh(priv);
868 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
869 netdev_err(dev, "cannot register lbs_mesh attribute\n");
871 ret = 1;
874 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875 return ret;
879 int lbs_deinit_mesh(struct lbs_private *priv)
881 struct net_device *dev = priv->dev;
882 int ret = 0;
884 lbs_deb_enter(LBS_DEB_MESH);
886 if (priv->mesh_tlv) {
887 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
888 ret = 1;
891 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
892 return ret;
897 * lbs_mesh_stop - close the mshX interface
899 * @dev: A pointer to &net_device structure
900 * returns: 0
902 static int lbs_mesh_stop(struct net_device *dev)
904 struct lbs_private *priv = dev->ml_priv;
906 lbs_deb_enter(LBS_DEB_MESH);
907 lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
909 spin_lock_irq(&priv->driver_lock);
911 netif_stop_queue(dev);
912 netif_carrier_off(dev);
914 spin_unlock_irq(&priv->driver_lock);
916 schedule_work(&priv->mcast_work);
918 lbs_deb_leave(LBS_DEB_MESH);
919 return 0;
923 * lbs_mesh_dev_open - open the mshX interface
925 * @dev: A pointer to &net_device structure
926 * returns: 0 or -EBUSY if monitor mode active
928 static int lbs_mesh_dev_open(struct net_device *dev)
930 struct lbs_private *priv = dev->ml_priv;
931 int ret = 0;
933 lbs_deb_enter(LBS_DEB_NET);
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, priv->channel);
952 out:
953 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
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_multicast_list = 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 int ret = 0;
976 lbs_deb_enter(LBS_DEB_MESH);
978 /* Allocate a virtual mesh device */
979 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
980 if (!mesh_dev) {
981 lbs_deb_mesh("init mshX device failed\n");
982 ret = -ENOMEM;
983 goto done;
985 mesh_dev->ml_priv = priv;
986 priv->mesh_dev = mesh_dev;
988 mesh_dev->netdev_ops = &mesh_netdev_ops;
989 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
990 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
992 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
994 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
995 /* Register virtual mesh interface */
996 ret = register_netdev(mesh_dev);
997 if (ret) {
998 pr_err("cannot register mshX virtual interface\n");
999 goto err_free;
1002 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1003 if (ret)
1004 goto err_unregister;
1006 lbs_persist_config_init(mesh_dev);
1008 /* Everything successful */
1009 ret = 0;
1010 goto done;
1012 err_unregister:
1013 unregister_netdev(mesh_dev);
1015 err_free:
1016 free_netdev(mesh_dev);
1018 done:
1019 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1020 return ret;
1023 void lbs_remove_mesh(struct lbs_private *priv)
1025 struct net_device *mesh_dev;
1027 mesh_dev = priv->mesh_dev;
1028 if (!mesh_dev)
1029 return;
1031 lbs_deb_enter(LBS_DEB_MESH);
1032 netif_stop_queue(mesh_dev);
1033 netif_carrier_off(mesh_dev);
1034 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1035 lbs_persist_config_remove(mesh_dev);
1036 unregister_netdev(mesh_dev);
1037 priv->mesh_dev = NULL;
1038 free_netdev(mesh_dev);
1039 lbs_deb_leave(LBS_DEB_MESH);
1043 /***************************************************************************
1044 * Sending and receiving
1046 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1047 struct net_device *dev, struct rxpd *rxpd)
1049 if (priv->mesh_dev) {
1050 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1051 if (rxpd->rx_control & RxPD_MESH_FRAME)
1052 dev = priv->mesh_dev;
1053 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1054 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1055 dev = priv->mesh_dev;
1058 return dev;
1062 void lbs_mesh_set_txpd(struct lbs_private *priv,
1063 struct net_device *dev, struct txpd *txpd)
1065 if (dev == priv->mesh_dev) {
1066 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1067 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1068 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1069 txpd->u.bss.bss_num = MESH_IFACE_ID;
1074 /***************************************************************************
1075 * Ethtool related
1078 static const char * const mesh_stat_strings[] = {
1079 "drop_duplicate_bcast",
1080 "drop_ttl_zero",
1081 "drop_no_fwd_route",
1082 "drop_no_buffers",
1083 "fwded_unicast_cnt",
1084 "fwded_bcast_cnt",
1085 "drop_blind_table",
1086 "tx_failed_cnt"
1089 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1090 struct ethtool_stats *stats, uint64_t *data)
1092 struct lbs_private *priv = dev->ml_priv;
1093 struct cmd_ds_mesh_access mesh_access;
1094 int ret;
1096 lbs_deb_enter(LBS_DEB_ETHTOOL);
1098 /* Get Mesh Statistics */
1099 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1101 if (ret) {
1102 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1103 return;
1106 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1107 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1108 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1109 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1110 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1111 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1112 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1113 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1115 data[0] = priv->mstats.fwd_drop_rbt;
1116 data[1] = priv->mstats.fwd_drop_ttl;
1117 data[2] = priv->mstats.fwd_drop_noroute;
1118 data[3] = priv->mstats.fwd_drop_nobuf;
1119 data[4] = priv->mstats.fwd_unicast_cnt;
1120 data[5] = priv->mstats.fwd_bcast_cnt;
1121 data[6] = priv->mstats.drop_blind;
1122 data[7] = priv->mstats.tx_failed_cnt;
1124 lbs_deb_enter(LBS_DEB_ETHTOOL);
1127 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1129 struct lbs_private *priv = dev->ml_priv;
1131 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1132 return MESH_STATS_NUM;
1134 return -EOPNOTSUPP;
1137 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1138 uint32_t stringset, uint8_t *s)
1140 int i;
1142 lbs_deb_enter(LBS_DEB_ETHTOOL);
1144 switch (stringset) {
1145 case ETH_SS_STATS:
1146 for (i = 0; i < MESH_STATS_NUM; i++) {
1147 memcpy(s + i * ETH_GSTRING_LEN,
1148 mesh_stat_strings[i],
1149 ETH_GSTRING_LEN);
1151 break;
1153 lbs_deb_enter(LBS_DEB_ETHTOOL);