Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / drivers / net / wireless / libertas / mesh.c
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
39         lbs_deb_leave(LBS_DEB_CMD);
40         return ret;
41 }
42
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)
46 {
47         int ret;
48         u16 command = CMD_MESH_CONFIG_OLD;
49
50         lbs_deb_enter(LBS_DEB_CMD);
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 |
58                           (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
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
69         lbs_deb_leave(LBS_DEB_CMD);
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
79         if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
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;
96         DECLARE_SSID_BUF(ssid);
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) {
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;
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
132
133 /***************************************************************************
134  * Mesh sysfs support
135  */
136
137 /*
138  * Attributes exported through sysfs
139  */
140
141 /**
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
146  */
147 static ssize_t lbs_anycast_get(struct device *dev,
148                 struct device_attribute *attr, char * buf)
149 {
150         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
151         struct cmd_ds_mesh_access mesh_access;
152         int ret;
153
154         memset(&mesh_access, 0, sizeof(mesh_access));
155
156         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
157         if (ret)
158                 return ret;
159
160         return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
161 }
162
163 /**
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
169  */
170 static ssize_t lbs_anycast_set(struct device *dev,
171                 struct device_attribute *attr, const char * buf, size_t count)
172 {
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;
177
178         memset(&mesh_access, 0, sizeof(mesh_access));
179         sscanf(buf, "%x", &datum);
180         mesh_access.data[0] = cpu_to_le32(datum);
181
182         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
183         if (ret)
184                 return ret;
185
186         return strlen(buf);
187 }
188
189 /**
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
194  */
195 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
196                 struct device_attribute *attr, char *buf)
197 {
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;
202
203         memset(&mesh_access, 0, sizeof(mesh_access));
204         mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
205
206         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
207                         &mesh_access);
208         if (ret)
209                 return ret;
210
211         retry_limit = le32_to_cpu(mesh_access.data[1]);
212         return snprintf(buf, 10, "%d\n", retry_limit);
213 }
214
215 /**
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
221  */
222 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
223                 struct device_attribute *attr, const char *buf, size_t count)
224 {
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;
229
230         memset(&mesh_access, 0, sizeof(mesh_access));
231         mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
232
233         if (!strict_strtoul(buf, 10, &retry_limit))
234                 return -ENOTSUPP;
235         if (retry_limit > 15)
236                 return -ENOTSUPP;
237
238         mesh_access.data[1] = cpu_to_le32(retry_limit);
239
240         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
241                         &mesh_access);
242         if (ret)
243                 return ret;
244
245         return strlen(buf);
246 }
247
248 /**
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
253  */
254 static ssize_t lbs_mesh_get(struct device *dev,
255                 struct device_attribute *attr, char * buf)
256 {
257         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
258         return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
259 }
260
261 /**
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
267  */
268 static ssize_t lbs_mesh_set(struct device *dev,
269                 struct device_attribute *attr, const char * buf, size_t count)
270 {
271         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
272         int enable;
273
274         sscanf(buf, "%x", &enable);
275         enable = !!enable;
276         if (enable == !!priv->mesh_dev)
277                 return count;
278
279         if (enable)
280                 lbs_add_mesh(priv);
281         else
282                 lbs_remove_mesh(priv);
283
284         return count;
285 }
286
287 /*
288  * lbs_mesh attribute to be exported per ethX interface
289  * through sysfs (/sys/class/net/ethX/lbs_mesh)
290  */
291 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
292
293 /*
294  * anycast_mask attribute to be exported per mshX interface
295  * through sysfs (/sys/class/net/mshX/anycast_mask)
296  */
297 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
298
299 /*
300  * prb_rsp_limit attribute to be exported per mshX interface
301  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
302  */
303 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
304                 lbs_prb_rsp_limit_set);
305
306 static struct attribute *lbs_mesh_sysfs_entries[] = {
307         &dev_attr_anycast_mask.attr,
308         &dev_attr_prb_rsp_limit.attr,
309         NULL,
310 };
311
312 static const struct attribute_group lbs_mesh_attr_group = {
313         .attrs = lbs_mesh_sysfs_entries,
314 };
315
316
317 /***************************************************************************
318  * Persistent configuration support
319  */
320
321 static int mesh_get_default_parameters(struct device *dev,
322                                        struct mrvl_mesh_defaults *defs)
323 {
324         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
325         struct cmd_ds_mesh_config cmd;
326         int ret;
327
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);
331
332         if (ret)
333                 return -EOPNOTSUPP;
334
335         memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
336
337         return 0;
338 }
339
340 /**
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
345  */
346 static ssize_t bootflag_get(struct device *dev,
347                             struct device_attribute *attr, char *buf)
348 {
349         struct mrvl_mesh_defaults defs;
350         int ret;
351
352         ret = mesh_get_default_parameters(dev, &defs);
353
354         if (ret)
355                 return ret;
356
357         return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
358 }
359
360 /**
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
366  */
367 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
368                             const char *buf, size_t count)
369 {
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;
374
375         memset(&cmd, 0, sizeof(cmd));
376         ret = sscanf(buf, "%d", &datum);
377         if ((ret != 1) || (datum > 1))
378                 return -EINVAL;
379
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;
386
387         return strlen(buf);
388 }
389
390 /**
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
395  */
396 static ssize_t boottime_get(struct device *dev,
397                             struct device_attribute *attr, char *buf)
398 {
399         struct mrvl_mesh_defaults defs;
400         int ret;
401
402         ret = mesh_get_default_parameters(dev, &defs);
403
404         if (ret)
405                 return ret;
406
407         return snprintf(buf, 12, "%d\n", defs.boottime);
408 }
409
410 /**
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
416  */
417 static ssize_t boottime_set(struct device *dev,
418                 struct device_attribute *attr, const char *buf, size_t count)
419 {
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;
424
425         memset(&cmd, 0, sizeof(cmd));
426         ret = sscanf(buf, "%d", &datum);
427         if ((ret != 1) || (datum > 255))
428                 return -EINVAL;
429
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.
437          */
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;
445
446         return strlen(buf);
447 }
448
449 /**
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
454  */
455 static ssize_t channel_get(struct device *dev,
456                            struct device_attribute *attr, char *buf)
457 {
458         struct mrvl_mesh_defaults defs;
459         int ret;
460
461         ret = mesh_get_default_parameters(dev, &defs);
462
463         if (ret)
464                 return ret;
465
466         return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
467 }
468
469 /**
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
475  */
476 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
477                            const char *buf, size_t count)
478 {
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;
483
484         memset(&cmd, 0, sizeof(cmd));
485         ret = sscanf(buf, "%d", &datum);
486         if (ret != 1 || datum < 1 || datum > 11)
487                 return -EINVAL;
488
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;
495
496         return strlen(buf);
497 }
498
499 /**
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
504  */
505 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
506                            char *buf)
507 {
508         struct mrvl_mesh_defaults defs;
509         int ret;
510
511         ret = mesh_get_default_parameters(dev, &defs);
512
513         if (ret)
514                 return ret;
515
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;
519         }
520
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';
524
525         return defs.meshie.val.mesh_id_len + 1;
526 }
527
528 /**
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
534  */
535 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
536                            const char *buf, size_t count)
537 {
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;
544
545         if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
546                 return -EINVAL;
547
548         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
549         ie = (struct mrvl_meshie *) &cmd.data[0];
550
551         /* fetch all other Information Element parameters */
552         ret = mesh_get_default_parameters(dev, &defs);
553
554         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
555
556         /* transfer IE elements */
557         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
558
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;
565
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;
570
571         return strlen(buf);
572 }
573
574 /**
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
579  */
580 static ssize_t protocol_id_get(struct device *dev,
581                                struct device_attribute *attr, char *buf)
582 {
583         struct mrvl_mesh_defaults defs;
584         int ret;
585
586         ret = mesh_get_default_parameters(dev, &defs);
587
588         if (ret)
589                 return ret;
590
591         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
592 }
593
594 /**
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
600  */
601 static ssize_t protocol_id_set(struct device *dev,
602                 struct device_attribute *attr, const char *buf, size_t count)
603 {
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;
610
611         memset(&cmd, 0, sizeof(cmd));
612         ret = sscanf(buf, "%d", &datum);
613         if ((ret != 1) || (datum > 255))
614                 return -EINVAL;
615
616         /* fetch all other Information Element parameters */
617         ret = mesh_get_default_parameters(dev, &defs);
618
619         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
620
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;
626
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;
631
632         return strlen(buf);
633 }
634
635 /**
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
640  */
641 static ssize_t metric_id_get(struct device *dev,
642                 struct device_attribute *attr, char *buf)
643 {
644         struct mrvl_mesh_defaults defs;
645         int ret;
646
647         ret = mesh_get_default_parameters(dev, &defs);
648
649         if (ret)
650                 return ret;
651
652         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
653 }
654
655 /**
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
661  */
662 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
663                              const char *buf, size_t count)
664 {
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;
671
672         memset(&cmd, 0, sizeof(cmd));
673         ret = sscanf(buf, "%d", &datum);
674         if ((ret != 1) || (datum > 255))
675                 return -EINVAL;
676
677         /* fetch all other Information Element parameters */
678         ret = mesh_get_default_parameters(dev, &defs);
679
680         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
681
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;
687
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;
692
693         return strlen(buf);
694 }
695
696 /**
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
701  */
702 static ssize_t capability_get(struct device *dev,
703                 struct device_attribute *attr, char *buf)
704 {
705         struct mrvl_mesh_defaults defs;
706         int ret;
707
708         ret = mesh_get_default_parameters(dev, &defs);
709
710         if (ret)
711                 return ret;
712
713         return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
714 }
715
716 /**
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
722  */
723 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
724                               const char *buf, size_t count)
725 {
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;
732
733         memset(&cmd, 0, sizeof(cmd));
734         ret = sscanf(buf, "%d", &datum);
735         if ((ret != 1) || (datum > 255))
736                 return -EINVAL;
737
738         /* fetch all other Information Element parameters */
739         ret = mesh_get_default_parameters(dev, &defs);
740
741         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
742
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;
748
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;
753
754         return strlen(buf);
755 }
756
757
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);
765
766 static struct attribute *boot_opts_attrs[] = {
767         &dev_attr_bootflag.attr,
768         &dev_attr_boottime.attr,
769         &dev_attr_channel.attr,
770         NULL
771 };
772
773 static const struct attribute_group boot_opts_group = {
774         .name = "boot_options",
775         .attrs = boot_opts_attrs,
776 };
777
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
784 };
785
786 static const struct attribute_group mesh_ie_group = {
787         .name = "mesh_ie",
788         .attrs = mesh_ie_attrs,
789 };
790
791 static void lbs_persist_config_init(struct net_device *dev)
792 {
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);
796 }
797
798 static void lbs_persist_config_remove(struct net_device *dev)
799 {
800         sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
801         sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
802 }
803
804
805 /***************************************************************************
806  * Initializing and starting, stopping mesh
807  */
808
809 /*
810  * Check mesh FW version and appropriately send the mesh start
811  * command
812  */
813 int lbs_init_mesh(struct lbs_private *priv)
814 {
815         struct net_device *dev = priv->dev;
816         int ret = 0;
817
818         lbs_deb_enter(LBS_DEB_MESH);
819
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. */
831
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 */
838
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;
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,
855                                     priv->channel))
856                         priv->mesh_tlv = 0;
857         }
858
859         /* Stop meshing until interface is brought up */
860         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
861
862         if (priv->mesh_tlv) {
863                 sprintf(priv->mesh_ssid, "mesh");
864                 priv->mesh_ssid_len = 4;
865
866                 lbs_add_mesh(priv);
867
868                 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
869                         netdev_err(dev, "cannot register lbs_mesh attribute\n");
870
871                 ret = 1;
872         }
873
874         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
875         return ret;
876 }
877
878
879 int lbs_deinit_mesh(struct lbs_private *priv)
880 {
881         struct net_device *dev = priv->dev;
882         int ret = 0;
883
884         lbs_deb_enter(LBS_DEB_MESH);
885
886         if (priv->mesh_tlv) {
887                 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
888                 ret = 1;
889         }
890
891         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
892         return ret;
893 }
894
895
896 /**
897  * lbs_mesh_stop - close the mshX interface
898  *
899  * @dev:        A pointer to &net_device structure
900  * returns:     0
901  */
902 static int lbs_mesh_stop(struct net_device *dev)
903 {
904         struct lbs_private *priv = dev->ml_priv;
905
906         lbs_deb_enter(LBS_DEB_MESH);
907         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel);
908
909         spin_lock_irq(&priv->driver_lock);
910
911         netif_stop_queue(dev);
912         netif_carrier_off(dev);
913
914         spin_unlock_irq(&priv->driver_lock);
915
916         schedule_work(&priv->mcast_work);
917
918         lbs_deb_leave(LBS_DEB_MESH);
919         return 0;
920 }
921
922 /**
923  * lbs_mesh_dev_open - open the mshX interface
924  *
925  * @dev:        A pointer to &net_device structure
926  * returns:     0 or -EBUSY if monitor mode active
927  */
928 static int lbs_mesh_dev_open(struct net_device *dev)
929 {
930         struct lbs_private *priv = dev->ml_priv;
931         int ret = 0;
932
933         lbs_deb_enter(LBS_DEB_NET);
934
935         spin_lock_irq(&priv->driver_lock);
936
937         if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
938                 ret = -EBUSY;
939                 spin_unlock_irq(&priv->driver_lock);
940                 goto out;
941         }
942
943         netif_carrier_on(dev);
944
945         if (!priv->tx_pending_len)
946                 netif_wake_queue(dev);
947
948         spin_unlock_irq(&priv->driver_lock);
949
950         ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel);
951
952 out:
953         lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
954         return ret;
955 }
956
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,
963 };
964
965 /**
966  * lbs_add_mesh - add mshX interface
967  *
968  * @priv:       A pointer to the &struct lbs_private structure
969  * returns:     0 if successful, -X otherwise
970  */
971 static int lbs_add_mesh(struct lbs_private *priv)
972 {
973         struct net_device *mesh_dev = NULL;
974         int ret = 0;
975
976         lbs_deb_enter(LBS_DEB_MESH);
977
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;
984         }
985         mesh_dev->ml_priv = priv;
986         priv->mesh_dev = mesh_dev;
987
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);
991
992         SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
993
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;
1000         }
1001
1002         ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1003         if (ret)
1004                 goto err_unregister;
1005
1006         lbs_persist_config_init(mesh_dev);
1007
1008         /* Everything successful */
1009         ret = 0;
1010         goto done;
1011
1012 err_unregister:
1013         unregister_netdev(mesh_dev);
1014
1015 err_free:
1016         free_netdev(mesh_dev);
1017
1018 done:
1019         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
1020         return ret;
1021 }
1022
1023 void lbs_remove_mesh(struct lbs_private *priv)
1024 {
1025         struct net_device *mesh_dev;
1026
1027         mesh_dev = priv->mesh_dev;
1028         if (!mesh_dev)
1029                 return;
1030
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);
1040 }
1041
1042
1043 /***************************************************************************
1044  * Sending and receiving
1045  */
1046 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1047         struct net_device *dev, struct rxpd *rxpd)
1048 {
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;
1056                 }
1057         }
1058         return dev;
1059 }
1060
1061
1062 void lbs_mesh_set_txpd(struct lbs_private *priv,
1063         struct net_device *dev, struct txpd *txpd)
1064 {
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;
1070         }
1071 }
1072
1073
1074 /***************************************************************************
1075  * Ethtool related
1076  */
1077
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"
1087 };
1088
1089 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1090         struct ethtool_stats *stats, uint64_t *data)
1091 {
1092         struct lbs_private *priv = dev->ml_priv;
1093         struct cmd_ds_mesh_access mesh_access;
1094         int ret;
1095
1096         lbs_deb_enter(LBS_DEB_ETHTOOL);
1097
1098         /* Get Mesh Statistics */
1099         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1100
1101         if (ret) {
1102                 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1103                 return;
1104         }
1105
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]);
1114
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;
1123
1124         lbs_deb_enter(LBS_DEB_ETHTOOL);
1125 }
1126
1127 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1128 {
1129         struct lbs_private *priv = dev->ml_priv;
1130
1131         if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1132                 return MESH_STATS_NUM;
1133
1134         return -EOPNOTSUPP;
1135 }
1136
1137 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1138         uint32_t stringset, uint8_t *s)
1139 {
1140         int i;
1141
1142         lbs_deb_enter(LBS_DEB_ETHTOOL);
1143
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);
1150                 }
1151                 break;
1152         }
1153         lbs_deb_enter(LBS_DEB_ETHTOOL);
1154 }