Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mesh.c
Go to the documentation of this file.
1 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2 
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>
12 
13 #include "mesh.h"
14 #include "decl.h"
15 #include "cmd.h"
16 
17 
18 static int lbs_add_mesh(struct lbs_private *priv);
19 
20 /***************************************************************************
21  * Mesh command handling
22  */
23 
24 static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
25  struct cmd_ds_mesh_access *cmd)
26 {
27  int ret;
28 
29  lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
30 
31  cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
32  cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
33  cmd->hdr.result = 0;
34 
35  cmd->action = cpu_to_le16(cmd_action);
36 
37  ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
38 
40  return ret;
41 }
42 
43 static int __lbs_mesh_config_send(struct lbs_private *priv,
44  struct cmd_ds_mesh_config *cmd,
46 {
47  int ret;
49 
51 
52  /*
53  * Command id is 0xac for v10 FW along with mesh interface
54  * id in bits 14-13-12.
55  */
56  if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
57  command = CMD_MESH_CONFIG |
59 
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;
63 
64  cmd->type = cpu_to_le16(type);
65  cmd->action = cpu_to_le16(action);
66 
67  ret = lbs_cmd_with_response(priv, command, cmd);
68 
70  return ret;
71 }
72 
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)
76 {
77  int ret;
78 
80  return -EOPNOTSUPP;
81 
82  ret = __lbs_mesh_config_send(priv, cmd, action, type);
83  return ret;
84 }
85 
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.
90  */
91 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
92  uint16_t chan)
93 {
94  struct cmd_ds_mesh_config cmd;
95  struct mrvl_meshie *ie;
97 
98  memset(&cmd, 0, sizeof(cmd));
99  cmd.channel = cpu_to_le16(chan);
100  ie = (struct mrvl_meshie *)cmd.data;
101 
102  switch (action) {
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;
121  break;
122  default:
123  return -1;
124  }
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));
128 
129  return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
130 }
131 
133 {
134  priv->mesh_channel = channel;
135  return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
136 }
137 
138 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
139 {
140  return priv->mesh_channel ?: 1;
141 }
142 
143 /***************************************************************************
144  * Mesh sysfs support
145  */
146 
147 /*
148  * Attributes exported through sysfs
149  */
150 
157 static ssize_t lbs_anycast_get(struct device *dev,
158  struct device_attribute *attr, char * buf)
159 {
160  struct lbs_private *priv = to_net_dev(dev)->ml_priv;
161  struct cmd_ds_mesh_access mesh_access;
162  int ret;
163 
164  memset(&mesh_access, 0, sizeof(mesh_access));
165 
166  ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
167  if (ret)
168  return ret;
169 
170  return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
171 }
172 
180 static ssize_t lbs_anycast_set(struct device *dev,
181  struct device_attribute *attr, const char * buf, size_t count)
182 {
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;
187 
188  memset(&mesh_access, 0, sizeof(mesh_access));
189  sscanf(buf, "%x", &datum);
190  mesh_access.data[0] = cpu_to_le32(datum);
191 
192  ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
193  if (ret)
194  return ret;
195 
196  return strlen(buf);
197 }
198 
205 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
206  struct device_attribute *attr, char *buf)
207 {
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;
212 
213  memset(&mesh_access, 0, sizeof(mesh_access));
214  mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
215 
216  ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
217  &mesh_access);
218  if (ret)
219  return ret;
220 
221  retry_limit = le32_to_cpu(mesh_access.data[1]);
222  return snprintf(buf, 10, "%d\n", retry_limit);
223 }
224 
232 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
233  struct device_attribute *attr, const char *buf, size_t count)
234 {
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;
239 
240  memset(&mesh_access, 0, sizeof(mesh_access));
241  mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
242 
243  if (!strict_strtoul(buf, 10, &retry_limit))
244  return -ENOTSUPP;
245  if (retry_limit > 15)
246  return -ENOTSUPP;
247 
248  mesh_access.data[1] = cpu_to_le32(retry_limit);
249 
250  ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
251  &mesh_access);
252  if (ret)
253  return ret;
254 
255  return strlen(buf);
256 }
257 
264 static ssize_t lbs_mesh_get(struct device *dev,
265  struct device_attribute *attr, char * buf)
266 {
267  struct lbs_private *priv = to_net_dev(dev)->ml_priv;
268  return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
269 }
270 
278 static ssize_t lbs_mesh_set(struct device *dev,
279  struct device_attribute *attr, const char * buf, size_t count)
280 {
281  struct lbs_private *priv = to_net_dev(dev)->ml_priv;
282  int enable;
283 
284  sscanf(buf, "%x", &enable);
285  enable = !!enable;
286  if (enable == !!priv->mesh_dev)
287  return count;
288 
289  if (enable)
290  lbs_add_mesh(priv);
291  else
292  lbs_remove_mesh(priv);
293 
294  return count;
295 }
296 
297 /*
298  * lbs_mesh attribute to be exported per ethX interface
299  * through sysfs (/sys/class/net/ethX/lbs_mesh)
300  */
301 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
302 
303 /*
304  * anycast_mask attribute to be exported per mshX interface
305  * through sysfs (/sys/class/net/mshX/anycast_mask)
306  */
307 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
308 
309 /*
310  * prb_rsp_limit attribute to be exported per mshX interface
311  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
312  */
313 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
314  lbs_prb_rsp_limit_set);
315 
316 static struct attribute *lbs_mesh_sysfs_entries[] = {
317  &dev_attr_anycast_mask.attr,
318  &dev_attr_prb_rsp_limit.attr,
319  NULL,
320 };
321 
322 static const struct attribute_group lbs_mesh_attr_group = {
323  .attrs = lbs_mesh_sysfs_entries,
324 };
325 
326 
327 /***************************************************************************
328  * Persistent configuration support
329  */
330 
331 static int mesh_get_default_parameters(struct device *dev,
332  struct mrvl_mesh_defaults *defs)
333 {
334  struct lbs_private *priv = to_net_dev(dev)->ml_priv;
335  struct cmd_ds_mesh_config cmd;
336  int ret;
337 
338  memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
339  ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
341 
342  if (ret)
343  return -EOPNOTSUPP;
344 
345  memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
346 
347  return 0;
348 }
349 
356 static ssize_t bootflag_get(struct device *dev,
357  struct device_attribute *attr, char *buf)
358 {
359  struct mrvl_mesh_defaults defs;
360  int ret;
361 
362  ret = mesh_get_default_parameters(dev, &defs);
363 
364  if (ret)
365  return ret;
366 
367  return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
368 }
369 
377 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
378  const char *buf, size_t count)
379 {
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;
384 
385  memset(&cmd, 0, sizeof(cmd));
386  ret = sscanf(buf, "%d", &datum);
387  if ((ret != 1) || (datum > 1))
388  return -EINVAL;
389 
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,
394  if (ret)
395  return ret;
396 
397  return strlen(buf);
398 }
399 
406 static ssize_t boottime_get(struct device *dev,
407  struct device_attribute *attr, char *buf)
408 {
409  struct mrvl_mesh_defaults defs;
410  int ret;
411 
412  ret = mesh_get_default_parameters(dev, &defs);
413 
414  if (ret)
415  return ret;
416 
417  return snprintf(buf, 12, "%d\n", defs.boottime);
418 }
419 
427 static ssize_t boottime_set(struct device *dev,
428  struct device_attribute *attr, const char *buf, size_t count)
429 {
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;
434 
435  memset(&cmd, 0, sizeof(cmd));
436  ret = sscanf(buf, "%d", &datum);
437  if ((ret != 1) || (datum > 255))
438  return -EINVAL;
439 
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.
447  */
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,
453  if (ret)
454  return ret;
455 
456  return strlen(buf);
457 }
458 
465 static ssize_t channel_get(struct device *dev,
466  struct device_attribute *attr, char *buf)
467 {
468  struct mrvl_mesh_defaults defs;
469  int ret;
470 
471  ret = mesh_get_default_parameters(dev, &defs);
472 
473  if (ret)
474  return ret;
475 
476  return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
477 }
478 
486 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
487  const char *buf, size_t count)
488 {
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;
493 
494  memset(&cmd, 0, sizeof(cmd));
495  ret = sscanf(buf, "%d", &datum);
496  if (ret != 1 || datum < 1 || datum > 11)
497  return -EINVAL;
498 
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,
503  if (ret)
504  return ret;
505 
506  return strlen(buf);
507 }
508 
515 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
516  char *buf)
517 {
518  struct mrvl_mesh_defaults defs;
519  int ret;
520 
521  ret = mesh_get_default_parameters(dev, &defs);
522 
523  if (ret)
524  return ret;
525 
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;
529  }
530 
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';
534 
535  return defs.meshie.val.mesh_id_len + 1;
536 }
537 
545 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
546  const char *buf, size_t count)
547 {
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;
554 
555  if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
556  return -EINVAL;
557 
558  memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
559  ie = (struct mrvl_meshie *) &cmd.data[0];
560 
561  /* fetch all other Information Element parameters */
562  ret = mesh_get_default_parameters(dev, &defs);
563 
564  cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
565 
566  /* transfer IE elements */
567  memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
568 
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;
575 
576  ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
578  if (ret)
579  return ret;
580 
581  return strlen(buf);
582 }
583 
590 static ssize_t protocol_id_get(struct device *dev,
591  struct device_attribute *attr, char *buf)
592 {
593  struct mrvl_mesh_defaults defs;
594  int ret;
595 
596  ret = mesh_get_default_parameters(dev, &defs);
597 
598  if (ret)
599  return ret;
600 
601  return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
602 }
603 
611 static ssize_t protocol_id_set(struct device *dev,
612  struct device_attribute *attr, const char *buf, size_t count)
613 {
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;
620 
621  memset(&cmd, 0, sizeof(cmd));
622  ret = sscanf(buf, "%d", &datum);
623  if ((ret != 1) || (datum > 255))
624  return -EINVAL;
625 
626  /* fetch all other Information Element parameters */
627  ret = mesh_get_default_parameters(dev, &defs);
628 
629  cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
630 
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;
636 
637  ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
639  if (ret)
640  return ret;
641 
642  return strlen(buf);
643 }
644 
651 static ssize_t metric_id_get(struct device *dev,
652  struct device_attribute *attr, char *buf)
653 {
654  struct mrvl_mesh_defaults defs;
655  int ret;
656 
657  ret = mesh_get_default_parameters(dev, &defs);
658 
659  if (ret)
660  return ret;
661 
662  return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
663 }
664 
672 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
673  const char *buf, size_t count)
674 {
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;
681 
682  memset(&cmd, 0, sizeof(cmd));
683  ret = sscanf(buf, "%d", &datum);
684  if ((ret != 1) || (datum > 255))
685  return -EINVAL;
686 
687  /* fetch all other Information Element parameters */
688  ret = mesh_get_default_parameters(dev, &defs);
689 
690  cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
691 
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;
697 
698  ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
700  if (ret)
701  return ret;
702 
703  return strlen(buf);
704 }
705 
712 static ssize_t capability_get(struct device *dev,
713  struct device_attribute *attr, char *buf)
714 {
715  struct mrvl_mesh_defaults defs;
716  int ret;
717 
718  ret = mesh_get_default_parameters(dev, &defs);
719 
720  if (ret)
721  return ret;
722 
723  return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
724 }
725 
733 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
734  const char *buf, size_t count)
735 {
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;
742 
743  memset(&cmd, 0, sizeof(cmd));
744  ret = sscanf(buf, "%d", &datum);
745  if ((ret != 1) || (datum > 255))
746  return -EINVAL;
747 
748  /* fetch all other Information Element parameters */
749  ret = mesh_get_default_parameters(dev, &defs);
750 
751  cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
752 
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;
758 
759  ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
761  if (ret)
762  return ret;
763 
764  return strlen(buf);
765 }
766 
767 
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);
775 
776 static struct attribute *boot_opts_attrs[] = {
777  &dev_attr_bootflag.attr,
778  &dev_attr_boottime.attr,
779  &dev_attr_channel.attr,
780  NULL
781 };
782 
783 static const struct attribute_group boot_opts_group = {
784  .name = "boot_options",
785  .attrs = boot_opts_attrs,
786 };
787 
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
794 };
795 
796 static const struct attribute_group mesh_ie_group = {
797  .name = "mesh_ie",
798  .attrs = mesh_ie_attrs,
799 };
800 
801 static void lbs_persist_config_init(struct net_device *dev)
802 {
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);
806 }
807 
808 static void lbs_persist_config_remove(struct net_device *dev)
809 {
810  sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
811  sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
812 }
813 
814 
815 /***************************************************************************
816  * Initializing and starting, stopping mesh
817  */
818 
819 /*
820  * Check mesh FW version and appropriately send the mesh start
821  * command
822  */
823 int lbs_init_mesh(struct lbs_private *priv)
824 {
825  int ret = 0;
826 
828 
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. */
840 
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 */
847 
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;
853  }
854  } else
855  if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
857  /* 10.0.0.pXX new firmwares should succeed with TLV
858  * 0x100+37; Do not invoke command with old TLV.
859  */
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;
863  }
864 
865  /* Stop meshing until interface is brought up */
866  lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
867 
868  if (priv->mesh_tlv) {
869  sprintf(priv->mesh_ssid, "mesh");
870  priv->mesh_ssid_len = 4;
871  ret = 1;
872  }
873 
874  lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875  return ret;
876 }
877 
878 void lbs_start_mesh(struct lbs_private *priv)
879 {
880  lbs_add_mesh(priv);
881 
882  if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
883  netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
884 }
885 
886 int lbs_deinit_mesh(struct lbs_private *priv)
887 {
888  struct net_device *dev = priv->dev;
889  int ret = 0;
890 
892 
893  if (priv->mesh_tlv) {
894  device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
895  ret = 1;
896  }
897 
898  lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
899  return ret;
900 }
901 
902 
909 static int lbs_mesh_stop(struct net_device *dev)
910 {
911  struct lbs_private *priv = dev->ml_priv;
912 
914  lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
915  lbs_mesh_get_channel(priv));
916 
917  spin_lock_irq(&priv->driver_lock);
918 
919  netif_stop_queue(dev);
920  netif_carrier_off(dev);
921 
922  spin_unlock_irq(&priv->driver_lock);
923 
924  lbs_update_mcast(priv);
925  if (!lbs_iface_active(priv))
926  lbs_stop_iface(priv);
927 
929  return 0;
930 }
931 
938 static int lbs_mesh_dev_open(struct net_device *dev)
939 {
940  struct lbs_private *priv = dev->ml_priv;
941  int ret = 0;
942 
944  if (!priv->iface_running) {
945  ret = lbs_start_iface(priv);
946  if (ret)
947  goto out;
948  }
949 
950  spin_lock_irq(&priv->driver_lock);
951 
952  if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
953  ret = -EBUSY;
954  spin_unlock_irq(&priv->driver_lock);
955  goto out;
956  }
957 
958  netif_carrier_on(dev);
959 
960  if (!priv->tx_pending_len)
961  netif_wake_queue(dev);
962 
963  spin_unlock_irq(&priv->driver_lock);
964 
965  ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
966  lbs_mesh_get_channel(priv));
967 
968 out:
969  lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
970  return ret;
971 }
972 
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,
979 };
980 
987 static int lbs_add_mesh(struct lbs_private *priv)
988 {
989  struct net_device *mesh_dev = NULL;
990  struct wireless_dev *mesh_wdev;
991  int ret = 0;
992 
994 
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;
1001  }
1002 
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;
1008  }
1009 
1010  mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
1011  mesh_wdev->wiphy = priv->wdev->wiphy;
1012  mesh_wdev->netdev = mesh_dev;
1013 
1014  mesh_dev->ml_priv = priv;
1015  mesh_dev->ieee80211_ptr = mesh_wdev;
1016  priv->mesh_dev = mesh_dev;
1017 
1018  mesh_dev->netdev_ops = &mesh_netdev_ops;
1019  mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1020  memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
1021 
1022  SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1023 
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;
1030  }
1031 
1032  ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1033  if (ret)
1034  goto err_unregister;
1035 
1036  lbs_persist_config_init(mesh_dev);
1037 
1038  /* Everything successful */
1039  ret = 0;
1040  goto done;
1041 
1042 err_unregister:
1043  unregister_netdev(mesh_dev);
1044 
1045 err_free_netdev:
1046  free_netdev(mesh_dev);
1047 
1048 err_free_wdev:
1049  kfree(mesh_wdev);
1050 
1051 done:
1052  lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1053  return ret;
1054 }
1055 
1056 void lbs_remove_mesh(struct lbs_private *priv)
1057 {
1058  struct net_device *mesh_dev;
1059 
1060  mesh_dev = priv->mesh_dev;
1061  if (!mesh_dev)
1062  return;
1063 
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);
1074 }
1075 
1076 
1077 /***************************************************************************
1078  * Sending and receiving
1079  */
1081  struct net_device *dev, struct rxpd *rxpd)
1082 {
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;
1090  }
1091  }
1092  return dev;
1093 }
1094 
1095 
1096 void lbs_mesh_set_txpd(struct lbs_private *priv,
1097  struct net_device *dev, struct txpd *txpd)
1098 {
1099  if (dev == priv->mesh_dev) {
1100  if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1102  else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1103  txpd->u.bss.bss_num = MESH_IFACE_ID;
1104  }
1105 }
1106 
1107 
1108 /***************************************************************************
1109  * Ethtool related
1110  */
1111 
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"
1121 };
1122 
1124  struct ethtool_stats *stats, uint64_t *data)
1125 {
1126  struct lbs_private *priv = dev->ml_priv;
1127  struct cmd_ds_mesh_access mesh_access;
1128  int ret;
1129 
1131 
1132  /* Get Mesh Statistics */
1133  ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1134 
1135  if (ret) {
1136  memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1137  return;
1138  }
1139 
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]);
1148 
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;
1157 
1159 }
1160 
1162 {
1163  struct lbs_private *priv = dev->ml_priv;
1164 
1165  if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1166  return MESH_STATS_NUM;
1167 
1168  return -EOPNOTSUPP;
1169 }
1170 
1172  uint32_t stringset, uint8_t *s)
1173 {
1174  int i;
1175 
1177 
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);
1184  }
1185  break;
1186  }
1188 }