GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / marvell / libertas / mesh.c
1 // SPDX-License-Identifier: GPL-2.0
2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3
4 #include <linux/delay.h>
5 #include <linux/etherdevice.h>
6 #include <linux/hardirq.h>
7 #include <linux/netdevice.h>
8 #include <linux/if_ether.h>
9 #include <linux/if_arp.h>
10 #include <linux/kthread.h>
11 #include <linux/kfifo.h>
12 #include <net/cfg80211.h>
13
14 #include "mesh.h"
15 #include "decl.h"
16 #include "cmd.h"
17
18
19 static int lbs_add_mesh(struct lbs_private *priv);
20
21 /***************************************************************************
22  * Mesh command handling
23  */
24
25 static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
26                     struct cmd_ds_mesh_access *cmd)
27 {
28         int ret;
29
30         cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
31         cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
32         cmd->hdr.result = 0;
33
34         cmd->action = cpu_to_le16(cmd_action);
35
36         ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
37
38         return ret;
39 }
40
41 static int __lbs_mesh_config_send(struct lbs_private *priv,
42                                   struct cmd_ds_mesh_config *cmd,
43                                   uint16_t action, uint16_t type)
44 {
45         int ret;
46         u16 command = CMD_MESH_CONFIG_OLD;
47
48         /*
49          * Command id is 0xac for v10 FW along with mesh interface
50          * id in bits 14-13-12.
51          */
52         if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
53                 command = CMD_MESH_CONFIG |
54                           (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
55
56         cmd->hdr.command = cpu_to_le16(command);
57         cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
58         cmd->hdr.result = 0;
59
60         cmd->type = cpu_to_le16(type);
61         cmd->action = cpu_to_le16(action);
62
63         ret = lbs_cmd_with_response(priv, command, cmd);
64
65         return ret;
66 }
67
68 static int lbs_mesh_config_send(struct lbs_private *priv,
69                          struct cmd_ds_mesh_config *cmd,
70                          uint16_t action, uint16_t type)
71 {
72         int ret;
73
74         if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
75                 return -EOPNOTSUPP;
76
77         ret = __lbs_mesh_config_send(priv, cmd, action, type);
78         return ret;
79 }
80
81 /* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
82  * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
83  * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
84  * lbs_mesh_config_send.
85  */
86 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
87                 uint16_t chan)
88 {
89         struct wireless_dev *mesh_wdev;
90         struct cmd_ds_mesh_config cmd;
91         struct mrvl_meshie *ie;
92
93         memset(&cmd, 0, sizeof(cmd));
94         cmd.channel = cpu_to_le16(chan);
95         ie = (struct mrvl_meshie *)cmd.data;
96
97         switch (action) {
98         case CMD_ACT_MESH_CONFIG_START:
99                 ie->id = WLAN_EID_VENDOR_SPECIFIC;
100                 ie->val.oui[0] = 0x00;
101                 ie->val.oui[1] = 0x50;
102                 ie->val.oui[2] = 0x43;
103                 ie->val.type = MARVELL_MESH_IE_TYPE;
104                 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
105                 ie->val.version = MARVELL_MESH_IE_VERSION;
106                 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
107                 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
108                 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
109
110                 if (priv->mesh_dev) {
111                         mesh_wdev = priv->mesh_dev->ieee80211_ptr;
112                         ie->val.mesh_id_len = mesh_wdev->mesh_id_up_len;
113                         memcpy(ie->val.mesh_id, mesh_wdev->ssid,
114                                                 mesh_wdev->mesh_id_up_len);
115                 }
116
117                 ie->len = sizeof(struct mrvl_meshie_val) -
118                         IEEE80211_MAX_SSID_LEN + ie->val.mesh_id_len;
119
120                 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
121                 break;
122         case CMD_ACT_MESH_CONFIG_STOP:
123                 break;
124         default:
125                 return -1;
126         }
127         lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
128                     action, priv->mesh_tlv, chan, ie->val.mesh_id_len,
129                     ie->val.mesh_id);
130
131         return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
132 }
133
134 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
135 {
136         priv->mesh_channel = channel;
137         return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
138 }
139
140 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
141 {
142         return priv->mesh_channel ?: 1;
143 }
144
145 /***************************************************************************
146  * Mesh sysfs support
147  */
148
149 /*
150  * Attributes exported through sysfs
151  */
152
153 /**
154  * anycast_mask_show - Get function for sysfs attribute anycast_mask
155  * @dev: the &struct device
156  * @attr: device attributes
157  * @buf: buffer where data will be returned
158  */
159 static ssize_t anycast_mask_show(struct device *dev,
160                                  struct device_attribute *attr, char *buf)
161 {
162         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
163         struct cmd_ds_mesh_access mesh_access;
164         int ret;
165
166         memset(&mesh_access, 0, sizeof(mesh_access));
167
168         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
169         if (ret)
170                 return ret;
171
172         return sysfs_emit(buf, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
173 }
174
175 /**
176  * anycast_mask_store - Set function for sysfs attribute anycast_mask
177  * @dev: the &struct device
178  * @attr: device attributes
179  * @buf: buffer that contains new attribute value
180  * @count: size of buffer
181  */
182 static ssize_t anycast_mask_store(struct device *dev,
183                                   struct device_attribute *attr,
184                                   const char *buf, size_t count)
185 {
186         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
187         struct cmd_ds_mesh_access mesh_access;
188         uint32_t datum;
189         int ret;
190
191         memset(&mesh_access, 0, sizeof(mesh_access));
192         sscanf(buf, "%x", &datum);
193         mesh_access.data[0] = cpu_to_le32(datum);
194
195         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
196         if (ret)
197                 return ret;
198
199         return strlen(buf);
200 }
201
202 /**
203  * prb_rsp_limit_show - Get function for sysfs attribute prb_rsp_limit
204  * @dev: the &struct device
205  * @attr: device attributes
206  * @buf: buffer where data will be returned
207  */
208 static ssize_t prb_rsp_limit_show(struct device *dev,
209                                   struct device_attribute *attr, char *buf)
210 {
211         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
212         struct cmd_ds_mesh_access mesh_access;
213         int ret;
214         u32 retry_limit;
215
216         memset(&mesh_access, 0, sizeof(mesh_access));
217         mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
218
219         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
220                         &mesh_access);
221         if (ret)
222                 return ret;
223
224         retry_limit = le32_to_cpu(mesh_access.data[1]);
225         return sysfs_emit(buf, "%d\n", retry_limit);
226 }
227
228 /**
229  * prb_rsp_limit_store - Set function for sysfs attribute prb_rsp_limit
230  * @dev: the &struct device
231  * @attr: device attributes
232  * @buf: buffer that contains new attribute value
233  * @count: size of buffer
234  */
235 static ssize_t prb_rsp_limit_store(struct device *dev,
236                                    struct device_attribute *attr,
237                                    const char *buf, size_t count)
238 {
239         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
240         struct cmd_ds_mesh_access mesh_access;
241         int ret;
242         unsigned long retry_limit;
243
244         memset(&mesh_access, 0, sizeof(mesh_access));
245         mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
246
247         ret = kstrtoul(buf, 10, &retry_limit);
248         if (ret)
249                 return ret;
250         if (retry_limit > 15)
251                 return -ENOTSUPP;
252
253         mesh_access.data[1] = cpu_to_le32(retry_limit);
254
255         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
256                         &mesh_access);
257         if (ret)
258                 return ret;
259
260         return strlen(buf);
261 }
262
263 /**
264  * lbs_mesh_show - Get function for sysfs attribute mesh
265  * @dev: the &struct device
266  * @attr: device attributes
267  * @buf: buffer where data will be returned
268  */
269 static ssize_t lbs_mesh_show(struct device *dev,
270                              struct device_attribute *attr, char *buf)
271 {
272         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
273         return sysfs_emit(buf, "0x%X\n", !!priv->mesh_dev);
274 }
275
276 /**
277  * lbs_mesh_store - Set function for sysfs attribute mesh
278  * @dev: the &struct device
279  * @attr: device attributes
280  * @buf: buffer that contains new attribute value
281  * @count: size of buffer
282  */
283 static ssize_t lbs_mesh_store(struct device *dev,
284                               struct device_attribute *attr,
285                               const char *buf, size_t count)
286 {
287         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
288         int enable;
289
290         sscanf(buf, "%x", &enable);
291         enable = !!enable;
292         if (enable == !!priv->mesh_dev)
293                 return count;
294
295         if (enable)
296                 lbs_add_mesh(priv);
297         else
298                 lbs_remove_mesh(priv);
299
300         return count;
301 }
302
303 /*
304  * lbs_mesh attribute to be exported per ethX interface
305  * through sysfs (/sys/class/net/ethX/lbs_mesh)
306  */
307 static DEVICE_ATTR_RW(lbs_mesh);
308
309 /*
310  * anycast_mask attribute to be exported per mshX interface
311  * through sysfs (/sys/class/net/mshX/anycast_mask)
312  */
313 static DEVICE_ATTR_RW(anycast_mask);
314
315 /*
316  * prb_rsp_limit attribute to be exported per mshX interface
317  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
318  */
319 static DEVICE_ATTR_RW(prb_rsp_limit);
320
321 static struct attribute *lbs_mesh_sysfs_entries[] = {
322         &dev_attr_anycast_mask.attr,
323         &dev_attr_prb_rsp_limit.attr,
324         NULL,
325 };
326
327 static const struct attribute_group lbs_mesh_attr_group = {
328         .attrs = lbs_mesh_sysfs_entries,
329 };
330
331
332 /***************************************************************************
333  * Persistent configuration support
334  */
335
336 static int mesh_get_default_parameters(struct device *dev,
337                                        struct mrvl_mesh_defaults *defs)
338 {
339         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
340         struct cmd_ds_mesh_config cmd;
341         int ret;
342
343         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
344         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
345                                    CMD_TYPE_MESH_GET_DEFAULTS);
346
347         if (ret)
348                 return -EOPNOTSUPP;
349
350         memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
351
352         return 0;
353 }
354
355 /**
356  * bootflag_show - Get function for sysfs attribute bootflag
357  * @dev: the &struct device
358  * @attr: device attributes
359  * @buf: buffer where data will be returned
360  */
361 static ssize_t bootflag_show(struct device *dev,
362                              struct device_attribute *attr, char *buf)
363 {
364         struct mrvl_mesh_defaults defs;
365         int ret;
366
367         ret = mesh_get_default_parameters(dev, &defs);
368
369         if (ret)
370                 return ret;
371
372         return sysfs_emit(buf, "%d\n", le32_to_cpu(defs.bootflag));
373 }
374
375 /**
376  * bootflag_store - Set function for sysfs attribute bootflag
377  * @dev: the &struct device
378  * @attr: device attributes
379  * @buf: buffer that contains new attribute value
380  * @count: size of buffer
381  */
382 static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
383                               const char *buf, size_t count)
384 {
385         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
386         struct cmd_ds_mesh_config cmd;
387         uint32_t datum;
388         int ret;
389
390         memset(&cmd, 0, sizeof(cmd));
391         ret = sscanf(buf, "%d", &datum);
392         if ((ret != 1) || (datum > 1))
393                 return -EINVAL;
394
395         *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
396         cmd.length = cpu_to_le16(sizeof(uint32_t));
397         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
398                                    CMD_TYPE_MESH_SET_BOOTFLAG);
399         if (ret)
400                 return ret;
401
402         return strlen(buf);
403 }
404
405 /**
406  * boottime_show - Get function for sysfs attribute boottime
407  * @dev: the &struct device
408  * @attr: device attributes
409  * @buf: buffer where data will be returned
410  */
411 static ssize_t boottime_show(struct device *dev,
412                              struct device_attribute *attr, char *buf)
413 {
414         struct mrvl_mesh_defaults defs;
415         int ret;
416
417         ret = mesh_get_default_parameters(dev, &defs);
418
419         if (ret)
420                 return ret;
421
422         return sysfs_emit(buf, "%d\n", defs.boottime);
423 }
424
425 /**
426  * boottime_store - Set function for sysfs attribute boottime
427  * @dev: the &struct device
428  * @attr: device attributes
429  * @buf: buffer that contains new attribute value
430  * @count: size of buffer
431  */
432 static ssize_t boottime_store(struct device *dev,
433                               struct device_attribute *attr,
434                               const char *buf, size_t count)
435 {
436         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
437         struct cmd_ds_mesh_config cmd;
438         uint32_t datum;
439         int ret;
440
441         memset(&cmd, 0, sizeof(cmd));
442         ret = sscanf(buf, "%d", &datum);
443         if ((ret != 1) || (datum > 255))
444                 return -EINVAL;
445
446         /* A too small boot time will result in the device booting into
447          * standalone (no-host) mode before the host can take control of it,
448          * so the change will be hard to revert.  This may be a desired
449          * feature (e.g to configure a very fast boot time for devices that
450          * will not be attached to a host), but dangerous.  So I'm enforcing a
451          * lower limit of 20 seconds:  remove and recompile the driver if this
452          * does not work for you.
453          */
454         datum = (datum < 20) ? 20 : datum;
455         cmd.data[0] = datum;
456         cmd.length = cpu_to_le16(sizeof(uint8_t));
457         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
458                                    CMD_TYPE_MESH_SET_BOOTTIME);
459         if (ret)
460                 return ret;
461
462         return strlen(buf);
463 }
464
465 /**
466  * channel_show - Get function for sysfs attribute channel
467  * @dev: the &struct device
468  * @attr: device attributes
469  * @buf: buffer where data will be returned
470  */
471 static ssize_t channel_show(struct device *dev,
472                             struct device_attribute *attr, char *buf)
473 {
474         struct mrvl_mesh_defaults defs;
475         int ret;
476
477         ret = mesh_get_default_parameters(dev, &defs);
478
479         if (ret)
480                 return ret;
481
482         return sysfs_emit(buf, "%d\n", le16_to_cpu(defs.channel));
483 }
484
485 /**
486  * channel_store - Set function for sysfs attribute channel
487  * @dev: the &struct device
488  * @attr: device attributes
489  * @buf: buffer that contains new attribute value
490  * @count: size of buffer
491  */
492 static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
493                              const char *buf, size_t count)
494 {
495         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
496         struct cmd_ds_mesh_config cmd;
497         uint32_t datum;
498         int ret;
499
500         memset(&cmd, 0, sizeof(cmd));
501         ret = sscanf(buf, "%d", &datum);
502         if (ret != 1 || datum < 1 || datum > 11)
503                 return -EINVAL;
504
505         *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
506         cmd.length = cpu_to_le16(sizeof(uint16_t));
507         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
508                                    CMD_TYPE_MESH_SET_DEF_CHANNEL);
509         if (ret)
510                 return ret;
511
512         return strlen(buf);
513 }
514
515 /**
516  * mesh_id_show - Get function for sysfs attribute mesh_id
517  * @dev: the &struct device
518  * @attr: device attributes
519  * @buf: buffer where data will be returned
520  */
521 static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr,
522                             char *buf)
523 {
524         struct mrvl_mesh_defaults defs;
525         int ret;
526
527         ret = mesh_get_default_parameters(dev, &defs);
528
529         if (ret)
530                 return ret;
531
532         if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
533                 dev_err(dev, "inconsistent mesh ID length\n");
534                 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
535         }
536
537         memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
538         buf[defs.meshie.val.mesh_id_len] = '\n';
539         buf[defs.meshie.val.mesh_id_len + 1] = '\0';
540
541         return defs.meshie.val.mesh_id_len + 1;
542 }
543
544 /**
545  * mesh_id_store - Set function for sysfs attribute mesh_id
546  * @dev: the &struct device
547  * @attr: device attributes
548  * @buf: buffer that contains new attribute value
549  * @count: size of buffer
550  */
551 static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr,
552                              const char *buf, size_t count)
553 {
554         struct cmd_ds_mesh_config cmd;
555         struct mrvl_mesh_defaults defs;
556         struct mrvl_meshie *ie;
557         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
558         int len;
559         int ret;
560
561         if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
562                 return -EINVAL;
563
564         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
565         ie = (struct mrvl_meshie *) &cmd.data[0];
566
567         /* fetch all other Information Element parameters */
568         ret = mesh_get_default_parameters(dev, &defs);
569
570         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
571
572         /* transfer IE elements */
573         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
574
575         len = count - 1;
576         memcpy(ie->val.mesh_id, buf, len);
577         /* SSID len */
578         ie->val.mesh_id_len = len;
579         /* IE len */
580         ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
581
582         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
583                                    CMD_TYPE_MESH_SET_MESH_IE);
584         if (ret)
585                 return ret;
586
587         return strlen(buf);
588 }
589
590 /**
591  * protocol_id_show - Get function for sysfs attribute protocol_id
592  * @dev: the &struct device
593  * @attr: device attributes
594  * @buf: buffer where data will be returned
595  */
596 static ssize_t protocol_id_show(struct device *dev,
597                                 struct device_attribute *attr,
598                                 char *buf)
599 {
600         struct mrvl_mesh_defaults defs;
601         int ret;
602
603         ret = mesh_get_default_parameters(dev, &defs);
604
605         if (ret)
606                 return ret;
607
608         return sysfs_emit(buf, "%d\n", defs.meshie.val.active_protocol_id);
609 }
610
611 /**
612  * protocol_id_store - Set function for sysfs attribute protocol_id
613  * @dev: the &struct device
614  * @attr: device attributes
615  * @buf: buffer that contains new attribute value
616  * @count: size of buffer
617  */
618 static ssize_t protocol_id_store(struct device *dev,
619                                  struct device_attribute *attr,
620                                  const char *buf, size_t count)
621 {
622         struct cmd_ds_mesh_config cmd;
623         struct mrvl_mesh_defaults defs;
624         struct mrvl_meshie *ie;
625         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
626         uint32_t datum;
627         int ret;
628
629         memset(&cmd, 0, sizeof(cmd));
630         ret = sscanf(buf, "%d", &datum);
631         if ((ret != 1) || (datum > 255))
632                 return -EINVAL;
633
634         /* fetch all other Information Element parameters */
635         ret = mesh_get_default_parameters(dev, &defs);
636
637         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
638
639         /* transfer IE elements */
640         ie = (struct mrvl_meshie *) &cmd.data[0];
641         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
642         /* update protocol id */
643         ie->val.active_protocol_id = datum;
644
645         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
646                                    CMD_TYPE_MESH_SET_MESH_IE);
647         if (ret)
648                 return ret;
649
650         return strlen(buf);
651 }
652
653 /**
654  * metric_id_show - Get function for sysfs attribute metric_id
655  * @dev: the &struct device
656  * @attr: device attributes
657  * @buf: buffer where data will be returned
658  */
659 static ssize_t metric_id_show(struct device *dev,
660                               struct device_attribute *attr, char *buf)
661 {
662         struct mrvl_mesh_defaults defs;
663         int ret;
664
665         ret = mesh_get_default_parameters(dev, &defs);
666
667         if (ret)
668                 return ret;
669
670         return sysfs_emit(buf, "%d\n", defs.meshie.val.active_metric_id);
671 }
672
673 /**
674  * metric_id_store - Set function for sysfs attribute metric_id
675  * @dev: the &struct device
676  * @attr: device attributes
677  * @buf: buffer that contains new attribute value
678  * @count: size of buffer
679  */
680 static ssize_t metric_id_store(struct device *dev,
681                                struct device_attribute *attr,
682                                const char *buf, size_t count)
683 {
684         struct cmd_ds_mesh_config cmd;
685         struct mrvl_mesh_defaults defs;
686         struct mrvl_meshie *ie;
687         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
688         uint32_t datum;
689         int ret;
690
691         memset(&cmd, 0, sizeof(cmd));
692         ret = sscanf(buf, "%d", &datum);
693         if ((ret != 1) || (datum > 255))
694                 return -EINVAL;
695
696         /* fetch all other Information Element parameters */
697         ret = mesh_get_default_parameters(dev, &defs);
698
699         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
700
701         /* transfer IE elements */
702         ie = (struct mrvl_meshie *) &cmd.data[0];
703         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
704         /* update metric id */
705         ie->val.active_metric_id = datum;
706
707         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
708                                    CMD_TYPE_MESH_SET_MESH_IE);
709         if (ret)
710                 return ret;
711
712         return strlen(buf);
713 }
714
715 /**
716  * capability_show - Get function for sysfs attribute capability
717  * @dev: the &struct device
718  * @attr: device attributes
719  * @buf: buffer where data will be returned
720  */
721 static ssize_t capability_show(struct device *dev,
722                                struct device_attribute *attr, char *buf)
723 {
724         struct mrvl_mesh_defaults defs;
725         int ret;
726
727         ret = mesh_get_default_parameters(dev, &defs);
728
729         if (ret)
730                 return ret;
731
732         return sysfs_emit(buf, "%d\n", defs.meshie.val.mesh_capability);
733 }
734
735 /**
736  * capability_store - Set function for sysfs attribute capability
737  * @dev: the &struct device
738  * @attr: device attributes
739  * @buf: buffer that contains new attribute value
740  * @count: size of buffer
741  */
742 static ssize_t capability_store(struct device *dev,
743                                 struct device_attribute *attr,
744                                 const char *buf, size_t count)
745 {
746         struct cmd_ds_mesh_config cmd;
747         struct mrvl_mesh_defaults defs;
748         struct mrvl_meshie *ie;
749         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
750         uint32_t datum;
751         int ret;
752
753         memset(&cmd, 0, sizeof(cmd));
754         ret = sscanf(buf, "%d", &datum);
755         if ((ret != 1) || (datum > 255))
756                 return -EINVAL;
757
758         /* fetch all other Information Element parameters */
759         ret = mesh_get_default_parameters(dev, &defs);
760
761         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
762
763         /* transfer IE elements */
764         ie = (struct mrvl_meshie *) &cmd.data[0];
765         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
766         /* update value */
767         ie->val.mesh_capability = datum;
768
769         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
770                                    CMD_TYPE_MESH_SET_MESH_IE);
771         if (ret)
772                 return ret;
773
774         return strlen(buf);
775 }
776
777
778 static DEVICE_ATTR_RW(bootflag);
779 static DEVICE_ATTR_RW(boottime);
780 static DEVICE_ATTR_RW(channel);
781 static DEVICE_ATTR_RW(mesh_id);
782 static DEVICE_ATTR_RW(protocol_id);
783 static DEVICE_ATTR_RW(metric_id);
784 static DEVICE_ATTR_RW(capability);
785
786 static struct attribute *boot_opts_attrs[] = {
787         &dev_attr_bootflag.attr,
788         &dev_attr_boottime.attr,
789         &dev_attr_channel.attr,
790         NULL
791 };
792
793 static const struct attribute_group boot_opts_group = {
794         .name = "boot_options",
795         .attrs = boot_opts_attrs,
796 };
797
798 static struct attribute *mesh_ie_attrs[] = {
799         &dev_attr_mesh_id.attr,
800         &dev_attr_protocol_id.attr,
801         &dev_attr_metric_id.attr,
802         &dev_attr_capability.attr,
803         NULL
804 };
805
806 static const struct attribute_group mesh_ie_group = {
807         .name = "mesh_ie",
808         .attrs = mesh_ie_attrs,
809 };
810
811
812 /***************************************************************************
813  * Initializing and starting, stopping mesh
814  */
815
816 /*
817  * Check mesh FW version and appropriately send the mesh start
818  * command
819  */
820 void lbs_init_mesh(struct lbs_private *priv)
821 {
822         /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
823         /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
824         /* 5.110.22 have mesh command with 0xa3 command id */
825         /* 10.0.0.p0 FW brings in mesh config command with different id */
826         /* Check FW version MSB and initialize mesh_fw_ver */
827         if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
828                 /* Enable mesh, if supported, and work out which TLV it uses.
829                    0x100 + 291 is an unofficial value used in 5.110.20.pXX
830                    0x100 + 37 is the official value used in 5.110.21.pXX
831                    but we check them in that order because 20.pXX doesn't
832                    give an error -- it just silently fails. */
833
834                 /* 5.110.20.pXX firmware will fail the command if the channel
835                    doesn't match the existing channel. But only if the TLV
836                    is correct. If the channel is wrong, _BOTH_ versions will
837                    give an error to 0x100+291, and allow 0x100+37 to succeed.
838                    It's just that 5.110.20.pXX will not have done anything
839                    useful */
840
841                 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
842                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
843                         priv->mesh_tlv = TLV_TYPE_MESH_ID;
844                         if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
845                                 priv->mesh_tlv = 0;
846                 }
847         } else
848         if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
849                 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
850                 /* 10.0.0.pXX new firmwares should succeed with TLV
851                  * 0x100+37; Do not invoke command with old TLV.
852                  */
853                 priv->mesh_tlv = TLV_TYPE_MESH_ID;
854                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
855                         priv->mesh_tlv = 0;
856         }
857
858         /* Stop meshing until interface is brought up */
859         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
860 }
861
862 void lbs_start_mesh(struct lbs_private *priv)
863 {
864         lbs_add_mesh(priv);
865
866         if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
867                 netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
868 }
869
870 int lbs_deinit_mesh(struct lbs_private *priv)
871 {
872         struct net_device *dev = priv->dev;
873         int ret = 0;
874
875         if (priv->mesh_tlv) {
876                 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
877                 ret = 1;
878         }
879
880         return ret;
881 }
882
883
884 /**
885  * lbs_mesh_stop - close the mshX interface
886  *
887  * @dev:        A pointer to &net_device structure
888  * returns:     0
889  */
890 static int lbs_mesh_stop(struct net_device *dev)
891 {
892         struct lbs_private *priv = dev->ml_priv;
893
894         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
895                 lbs_mesh_get_channel(priv));
896
897         spin_lock_irq(&priv->driver_lock);
898
899         netif_stop_queue(dev);
900         netif_carrier_off(dev);
901
902         spin_unlock_irq(&priv->driver_lock);
903
904         lbs_update_mcast(priv);
905         if (!lbs_iface_active(priv))
906                 lbs_stop_iface(priv);
907
908         return 0;
909 }
910
911 /**
912  * lbs_mesh_dev_open - open the mshX interface
913  *
914  * @dev:        A pointer to &net_device structure
915  * returns:     0 or -EBUSY if monitor mode active
916  */
917 static int lbs_mesh_dev_open(struct net_device *dev)
918 {
919         struct lbs_private *priv = dev->ml_priv;
920         int ret = 0;
921
922         if (!priv->iface_running) {
923                 ret = lbs_start_iface(priv);
924                 if (ret)
925                         goto out;
926         }
927
928         spin_lock_irq(&priv->driver_lock);
929
930         if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
931                 ret = -EBUSY;
932                 spin_unlock_irq(&priv->driver_lock);
933                 goto out;
934         }
935
936         netif_carrier_on(dev);
937
938         if (!priv->tx_pending_len)
939                 netif_wake_queue(dev);
940
941         spin_unlock_irq(&priv->driver_lock);
942
943         ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
944                 lbs_mesh_get_channel(priv));
945
946 out:
947         return ret;
948 }
949
950 static const struct net_device_ops mesh_netdev_ops = {
951         .ndo_open               = lbs_mesh_dev_open,
952         .ndo_stop               = lbs_mesh_stop,
953         .ndo_start_xmit         = lbs_hard_start_xmit,
954         .ndo_set_mac_address    = lbs_set_mac_address,
955         .ndo_set_rx_mode        = lbs_set_multicast_list,
956 };
957
958 /**
959  * lbs_add_mesh - add mshX interface
960  *
961  * @priv:       A pointer to the &struct lbs_private structure
962  * returns:     0 if successful, -X otherwise
963  */
964 static int lbs_add_mesh(struct lbs_private *priv)
965 {
966         struct net_device *mesh_dev = NULL;
967         struct wireless_dev *mesh_wdev;
968         int ret = 0;
969
970         /* Allocate a virtual mesh device */
971         mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
972         if (!mesh_wdev) {
973                 lbs_deb_mesh("init mshX wireless device failed\n");
974                 ret = -ENOMEM;
975                 goto done;
976         }
977
978         mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
979         if (!mesh_dev) {
980                 lbs_deb_mesh("init mshX device failed\n");
981                 ret = -ENOMEM;
982                 goto err_free_wdev;
983         }
984
985         mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
986         mesh_wdev->wiphy = priv->wdev->wiphy;
987
988         if (priv->mesh_tlv) {
989                 sprintf(mesh_wdev->ssid, "mesh");
990                 mesh_wdev->mesh_id_up_len = 4;
991         }
992
993         mesh_wdev->netdev = mesh_dev;
994
995         mesh_dev->ml_priv = priv;
996         mesh_dev->ieee80211_ptr = mesh_wdev;
997         priv->mesh_dev = mesh_dev;
998
999         mesh_dev->netdev_ops = &mesh_netdev_ops;
1000         mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1001         eth_hw_addr_inherit(mesh_dev, priv->dev);
1002
1003         SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1004
1005         mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1006         mesh_dev->sysfs_groups[0] = &lbs_mesh_attr_group;
1007         mesh_dev->sysfs_groups[1] = &boot_opts_group;
1008         mesh_dev->sysfs_groups[2] = &mesh_ie_group;
1009
1010         /* Register virtual mesh interface */
1011         ret = register_netdev(mesh_dev);
1012         if (ret) {
1013                 pr_err("cannot register mshX virtual interface\n");
1014                 goto err_free_netdev;
1015         }
1016
1017         /* Everything successful */
1018         ret = 0;
1019         goto done;
1020
1021 err_free_netdev:
1022         free_netdev(mesh_dev);
1023
1024 err_free_wdev:
1025         kfree(mesh_wdev);
1026
1027 done:
1028         return ret;
1029 }
1030
1031 void lbs_remove_mesh(struct lbs_private *priv)
1032 {
1033         struct net_device *mesh_dev;
1034
1035         mesh_dev = priv->mesh_dev;
1036         if (!mesh_dev)
1037                 return;
1038
1039         netif_stop_queue(mesh_dev);
1040         netif_carrier_off(mesh_dev);
1041         unregister_netdev(mesh_dev);
1042         priv->mesh_dev = NULL;
1043         kfree(mesh_dev->ieee80211_ptr);
1044         free_netdev(mesh_dev);
1045 }
1046
1047
1048 /***************************************************************************
1049  * Sending and receiving
1050  */
1051 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1052         struct net_device *dev, struct rxpd *rxpd)
1053 {
1054         if (priv->mesh_dev) {
1055                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1056                         if (rxpd->rx_control & RxPD_MESH_FRAME)
1057                                 dev = priv->mesh_dev;
1058                 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1059                         if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1060                                 dev = priv->mesh_dev;
1061                 }
1062         }
1063         return dev;
1064 }
1065
1066
1067 void lbs_mesh_set_txpd(struct lbs_private *priv,
1068         struct net_device *dev, struct txpd *txpd)
1069 {
1070         if (dev == priv->mesh_dev) {
1071                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1072                         txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1073                 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1074                         txpd->u.bss.bss_num = MESH_IFACE_ID;
1075         }
1076 }
1077
1078
1079 /***************************************************************************
1080  * Ethtool related
1081  */
1082
1083 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1084         "drop_duplicate_bcast",
1085         "drop_ttl_zero",
1086         "drop_no_fwd_route",
1087         "drop_no_buffers",
1088         "fwded_unicast_cnt",
1089         "fwded_bcast_cnt",
1090         "drop_blind_table",
1091         "tx_failed_cnt"
1092 };
1093
1094 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1095         struct ethtool_stats *stats, uint64_t *data)
1096 {
1097         struct lbs_private *priv = dev->ml_priv;
1098         struct cmd_ds_mesh_access mesh_access;
1099         int ret;
1100
1101         /* Get Mesh Statistics */
1102         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1103
1104         if (ret) {
1105                 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1106                 return;
1107         }
1108
1109         priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1110         priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1111         priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1112         priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1113         priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1114         priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1115         priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1116         priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1117
1118         data[0] = priv->mstats.fwd_drop_rbt;
1119         data[1] = priv->mstats.fwd_drop_ttl;
1120         data[2] = priv->mstats.fwd_drop_noroute;
1121         data[3] = priv->mstats.fwd_drop_nobuf;
1122         data[4] = priv->mstats.fwd_unicast_cnt;
1123         data[5] = priv->mstats.fwd_bcast_cnt;
1124         data[6] = priv->mstats.drop_blind;
1125         data[7] = priv->mstats.tx_failed_cnt;
1126 }
1127
1128 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1129 {
1130         struct lbs_private *priv = dev->ml_priv;
1131
1132         if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1133                 return MESH_STATS_NUM;
1134
1135         return -EOPNOTSUPP;
1136 }
1137
1138 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1139         uint32_t stringset, uint8_t *s)
1140 {
1141         switch (stringset) {
1142         case ETH_SS_STATS:
1143                 memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1144                 break;
1145         }
1146 }