Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[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/netdevice.h>
6 #include <linux/if_ether.h>
7 #include <linux/if_arp.h>
8 #include <linux/kthread.h>
9 #include <linux/kfifo.h>
10 #include <net/cfg80211.h>
11
12 #include "mesh.h"
13 #include "decl.h"
14 #include "cmd.h"
15
16
17 /***************************************************************************
18  * Mesh sysfs support
19  */
20
21 /*
22  * Attributes exported through sysfs
23  */
24
25 /**
26  * lbs_anycast_get - Get function for sysfs attribute anycast_mask
27  * @dev: the &struct device
28  * @attr: device attributes
29  * @buf: buffer where data will be returned
30  */
31 static ssize_t lbs_anycast_get(struct device *dev,
32                 struct device_attribute *attr, char * buf)
33 {
34         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
35         struct cmd_ds_mesh_access mesh_access;
36         int ret;
37
38         memset(&mesh_access, 0, sizeof(mesh_access));
39
40         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
41         if (ret)
42                 return ret;
43
44         return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
45 }
46
47 /**
48  * lbs_anycast_set - Set function for sysfs attribute anycast_mask
49  * @dev: the &struct device
50  * @attr: device attributes
51  * @buf: buffer that contains new attribute value
52  * @count: size of buffer
53  */
54 static ssize_t lbs_anycast_set(struct device *dev,
55                 struct device_attribute *attr, const char * buf, size_t count)
56 {
57         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
58         struct cmd_ds_mesh_access mesh_access;
59         uint32_t datum;
60         int ret;
61
62         memset(&mesh_access, 0, sizeof(mesh_access));
63         sscanf(buf, "%x", &datum);
64         mesh_access.data[0] = cpu_to_le32(datum);
65
66         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
67         if (ret)
68                 return ret;
69
70         return strlen(buf);
71 }
72
73 /**
74  * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
75  * @dev: the &struct device
76  * @attr: device attributes
77  * @buf: buffer where data will be returned
78  */
79 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
80                 struct device_attribute *attr, char *buf)
81 {
82         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
83         struct cmd_ds_mesh_access mesh_access;
84         int ret;
85         u32 retry_limit;
86
87         memset(&mesh_access, 0, sizeof(mesh_access));
88         mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
89
90         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
91                         &mesh_access);
92         if (ret)
93                 return ret;
94
95         retry_limit = le32_to_cpu(mesh_access.data[1]);
96         return snprintf(buf, 10, "%d\n", retry_limit);
97 }
98
99 /**
100  * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
101  * @dev: the &struct device
102  * @attr: device attributes
103  * @buf: buffer that contains new attribute value
104  * @count: size of buffer
105  */
106 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
107                 struct device_attribute *attr, const char *buf, size_t count)
108 {
109         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
110         struct cmd_ds_mesh_access mesh_access;
111         int ret;
112         unsigned long retry_limit;
113
114         memset(&mesh_access, 0, sizeof(mesh_access));
115         mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
116
117         if (!strict_strtoul(buf, 10, &retry_limit))
118                 return -ENOTSUPP;
119         if (retry_limit > 15)
120                 return -ENOTSUPP;
121
122         mesh_access.data[1] = cpu_to_le32(retry_limit);
123
124         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
125                         &mesh_access);
126         if (ret)
127                 return ret;
128
129         return strlen(buf);
130 }
131
132 /**
133  * lbs_mesh_get - Get function for sysfs attribute mesh
134  * @dev: the &struct device
135  * @attr: device attributes
136  * @buf: buffer where data will be returned
137  */
138 static ssize_t lbs_mesh_get(struct device *dev,
139                 struct device_attribute *attr, char * buf)
140 {
141         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
142         return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
143 }
144
145 /**
146  * lbs_mesh_set - Set function for sysfs attribute mesh
147  * @dev: the &struct device
148  * @attr: device attributes
149  * @buf: buffer that contains new attribute value
150  * @count: size of buffer
151  */
152 static ssize_t lbs_mesh_set(struct device *dev,
153                 struct device_attribute *attr, const char * buf, size_t count)
154 {
155         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
156         int enable;
157         int ret, action = CMD_ACT_MESH_CONFIG_STOP;
158
159         sscanf(buf, "%x", &enable);
160         enable = !!enable;
161         if (enable == !!priv->mesh_dev)
162                 return count;
163         if (enable)
164                 action = CMD_ACT_MESH_CONFIG_START;
165         ret = lbs_mesh_config(priv, action, priv->channel);
166         if (ret)
167                 return ret;
168
169         if (enable)
170                 lbs_add_mesh(priv);
171         else
172                 lbs_remove_mesh(priv);
173
174         return count;
175 }
176
177 /*
178  * lbs_mesh attribute to be exported per ethX interface
179  * through sysfs (/sys/class/net/ethX/lbs_mesh)
180  */
181 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
182
183 /*
184  * anycast_mask attribute to be exported per mshX interface
185  * through sysfs (/sys/class/net/mshX/anycast_mask)
186  */
187 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
188
189 /*
190  * prb_rsp_limit attribute to be exported per mshX interface
191  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
192  */
193 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
194                 lbs_prb_rsp_limit_set);
195
196 static struct attribute *lbs_mesh_sysfs_entries[] = {
197         &dev_attr_anycast_mask.attr,
198         &dev_attr_prb_rsp_limit.attr,
199         NULL,
200 };
201
202 static struct attribute_group lbs_mesh_attr_group = {
203         .attrs = lbs_mesh_sysfs_entries,
204 };
205
206
207
208 /***************************************************************************
209  * Initializing and starting, stopping mesh
210  */
211
212 /*
213  * Check mesh FW version and appropriately send the mesh start
214  * command
215  */
216 int lbs_init_mesh(struct lbs_private *priv)
217 {
218         struct net_device *dev = priv->dev;
219         int ret = 0;
220
221         lbs_deb_enter(LBS_DEB_MESH);
222
223         priv->mesh_connect_status = LBS_DISCONNECTED;
224
225         /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
226         /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
227         /* 5.110.22 have mesh command with 0xa3 command id */
228         /* 10.0.0.p0 FW brings in mesh config command with different id */
229         /* Check FW version MSB and initialize mesh_fw_ver */
230         if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
231                 /* Enable mesh, if supported, and work out which TLV it uses.
232                    0x100 + 291 is an unofficial value used in 5.110.20.pXX
233                    0x100 + 37 is the official value used in 5.110.21.pXX
234                    but we check them in that order because 20.pXX doesn't
235                    give an error -- it just silently fails. */
236
237                 /* 5.110.20.pXX firmware will fail the command if the channel
238                    doesn't match the existing channel. But only if the TLV
239                    is correct. If the channel is wrong, _BOTH_ versions will
240                    give an error to 0x100+291, and allow 0x100+37 to succeed.
241                    It's just that 5.110.20.pXX will not have done anything
242                    useful */
243
244                 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
245                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
246                                     priv->channel)) {
247                         priv->mesh_tlv = TLV_TYPE_MESH_ID;
248                         if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
249                                             priv->channel))
250                                 priv->mesh_tlv = 0;
251                 }
252         } else
253         if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
254                 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
255                 /* 10.0.0.pXX new firmwares should succeed with TLV
256                  * 0x100+37; Do not invoke command with old TLV.
257                  */
258                 priv->mesh_tlv = TLV_TYPE_MESH_ID;
259                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
260                                     priv->channel))
261                         priv->mesh_tlv = 0;
262         }
263
264
265         if (priv->mesh_tlv) {
266                 sprintf(priv->mesh_ssid, "mesh");
267                 priv->mesh_ssid_len = 4;
268
269                 lbs_add_mesh(priv);
270
271                 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
272                         netdev_err(dev, "cannot register lbs_mesh attribute\n");
273
274                 ret = 1;
275         }
276
277         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
278         return ret;
279 }
280
281
282 int lbs_deinit_mesh(struct lbs_private *priv)
283 {
284         struct net_device *dev = priv->dev;
285         int ret = 0;
286
287         lbs_deb_enter(LBS_DEB_MESH);
288
289         if (priv->mesh_tlv) {
290                 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
291                 ret = 1;
292         }
293
294         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
295         return ret;
296 }
297
298
299 /**
300  * lbs_mesh_stop - close the mshX interface
301  *
302  * @dev:        A pointer to &net_device structure
303  * returns:     0
304  */
305 static int lbs_mesh_stop(struct net_device *dev)
306 {
307         struct lbs_private *priv = dev->ml_priv;
308
309         lbs_deb_enter(LBS_DEB_MESH);
310         spin_lock_irq(&priv->driver_lock);
311
312         priv->mesh_open = 0;
313         priv->mesh_connect_status = LBS_DISCONNECTED;
314
315         netif_stop_queue(dev);
316         netif_carrier_off(dev);
317
318         spin_unlock_irq(&priv->driver_lock);
319
320         schedule_work(&priv->mcast_work);
321
322         lbs_deb_leave(LBS_DEB_MESH);
323         return 0;
324 }
325
326 /**
327  * lbs_mesh_dev_open - open the mshX interface
328  *
329  * @dev:        A pointer to &net_device structure
330  * returns:     0 or -EBUSY if monitor mode active
331  */
332 static int lbs_mesh_dev_open(struct net_device *dev)
333 {
334         struct lbs_private *priv = dev->ml_priv;
335         int ret = 0;
336
337         lbs_deb_enter(LBS_DEB_NET);
338
339         spin_lock_irq(&priv->driver_lock);
340
341         if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
342                 ret = -EBUSY;
343                 goto out;
344         }
345
346         priv->mesh_open = 1;
347         priv->mesh_connect_status = LBS_CONNECTED;
348         netif_carrier_on(dev);
349
350         if (!priv->tx_pending_len)
351                 netif_wake_queue(dev);
352  out:
353
354         spin_unlock_irq(&priv->driver_lock);
355         lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
356         return ret;
357 }
358
359 static const struct net_device_ops mesh_netdev_ops = {
360         .ndo_open               = lbs_mesh_dev_open,
361         .ndo_stop               = lbs_mesh_stop,
362         .ndo_start_xmit         = lbs_hard_start_xmit,
363         .ndo_set_mac_address    = lbs_set_mac_address,
364         .ndo_set_multicast_list = lbs_set_multicast_list,
365 };
366
367 /**
368  * lbs_add_mesh - add mshX interface
369  *
370  * @priv:       A pointer to the &struct lbs_private structure
371  * returns:     0 if successful, -X otherwise
372  */
373 int lbs_add_mesh(struct lbs_private *priv)
374 {
375         struct net_device *mesh_dev = NULL;
376         int ret = 0;
377
378         lbs_deb_enter(LBS_DEB_MESH);
379
380         /* Allocate a virtual mesh device */
381         mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
382         if (!mesh_dev) {
383                 lbs_deb_mesh("init mshX device failed\n");
384                 ret = -ENOMEM;
385                 goto done;
386         }
387         mesh_dev->ml_priv = priv;
388         priv->mesh_dev = mesh_dev;
389
390         mesh_dev->netdev_ops = &mesh_netdev_ops;
391         mesh_dev->ethtool_ops = &lbs_ethtool_ops;
392         memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
393
394         SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
395
396         mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
397         /* Register virtual mesh interface */
398         ret = register_netdev(mesh_dev);
399         if (ret) {
400                 pr_err("cannot register mshX virtual interface\n");
401                 goto err_free;
402         }
403
404         ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
405         if (ret)
406                 goto err_unregister;
407
408         lbs_persist_config_init(mesh_dev);
409
410         /* Everything successful */
411         ret = 0;
412         goto done;
413
414 err_unregister:
415         unregister_netdev(mesh_dev);
416
417 err_free:
418         free_netdev(mesh_dev);
419
420 done:
421         lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
422         return ret;
423 }
424
425 void lbs_remove_mesh(struct lbs_private *priv)
426 {
427         struct net_device *mesh_dev;
428
429         mesh_dev = priv->mesh_dev;
430         if (!mesh_dev)
431                 return;
432
433         lbs_deb_enter(LBS_DEB_MESH);
434         netif_stop_queue(mesh_dev);
435         netif_carrier_off(mesh_dev);
436         sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
437         lbs_persist_config_remove(mesh_dev);
438         unregister_netdev(mesh_dev);
439         priv->mesh_dev = NULL;
440         free_netdev(mesh_dev);
441         lbs_deb_leave(LBS_DEB_MESH);
442 }
443
444
445
446 /***************************************************************************
447  * Sending and receiving
448  */
449 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
450         struct net_device *dev, struct rxpd *rxpd)
451 {
452         if (priv->mesh_dev) {
453                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
454                         if (rxpd->rx_control & RxPD_MESH_FRAME)
455                                 dev = priv->mesh_dev;
456                 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
457                         if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
458                                 dev = priv->mesh_dev;
459                 }
460         }
461         return dev;
462 }
463
464
465 void lbs_mesh_set_txpd(struct lbs_private *priv,
466         struct net_device *dev, struct txpd *txpd)
467 {
468         if (dev == priv->mesh_dev) {
469                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
470                         txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
471                 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
472                         txpd->u.bss.bss_num = MESH_IFACE_ID;
473         }
474 }
475
476
477 /***************************************************************************
478  * Mesh command handling
479  */
480
481 /**
482  * lbs_mesh_bt_add_del - Add or delete Mesh Blinding Table entries
483  *
484  * @priv:       A pointer to &struct lbs_private structure
485  * @add:        TRUE to add the entry, FALSE to delete it
486  * @addr1:      Destination address to blind or unblind
487  *
488  * returns:     0 on success, error on failure
489  */
490 int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
491 {
492         struct cmd_ds_bt_access cmd;
493         int ret = 0;
494
495         lbs_deb_enter(LBS_DEB_CMD);
496
497         BUG_ON(addr1 == NULL);
498
499         memset(&cmd, 0, sizeof(cmd));
500         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
501         memcpy(cmd.addr1, addr1, ETH_ALEN);
502         if (add) {
503                 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
504                 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
505                         addr1, ETH_ALEN);
506         } else {
507                 cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
508                 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
509                         addr1, ETH_ALEN);
510         }
511
512         ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
513
514         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
515         return ret;
516 }
517
518 /**
519  * lbs_mesh_bt_reset - Reset/clear the mesh blinding table
520  *
521  * @priv:       A pointer to &struct lbs_private structure
522  *
523  * returns:     0 on success, error on failure
524  */
525 int lbs_mesh_bt_reset(struct lbs_private *priv)
526 {
527         struct cmd_ds_bt_access cmd;
528         int ret = 0;
529
530         lbs_deb_enter(LBS_DEB_CMD);
531
532         memset(&cmd, 0, sizeof(cmd));
533         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
534         cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
535
536         ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
537
538         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
539         return ret;
540 }
541
542 /**
543  * lbs_mesh_bt_get_inverted - Gets the inverted status of the mesh
544  * blinding table
545  *
546  * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
547  * table, but an inverted table allows *only* traffic from nodes listed in
548  * the table.
549  *
550  * @priv:       A pointer to &struct lbs_private structure
551  * @inverted:   On success, TRUE if the blinding table is inverted,
552  *              FALSE if it is not inverted
553  *
554  * returns:     0 on success, error on failure
555  */
556 int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
557 {
558         struct cmd_ds_bt_access cmd;
559         int ret = 0;
560
561         lbs_deb_enter(LBS_DEB_CMD);
562
563         BUG_ON(inverted == NULL);
564
565         memset(&cmd, 0, sizeof(cmd));
566         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
567         cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
568
569         ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
570         if (ret == 0)
571                 *inverted = !!cmd.id;
572
573         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
574         return ret;
575 }
576
577 /**
578  * lbs_mesh_bt_set_inverted - Sets the inverted status of the mesh
579  * blinding table
580  *
581  * Normally the firmware "blinds" or ignores traffic from mesh nodes in the
582  * table, but an inverted table allows *only* traffic from nodes listed in
583  * the table.
584  *
585  * @priv:       A pointer to &struct lbs_private structure
586  * @inverted:   TRUE to invert the blinding table (only traffic from
587  *              listed nodes allowed), FALSE to return it
588  *              to normal state (listed nodes ignored)
589  *
590  * returns:     0 on success, error on failure
591  */
592 int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
593 {
594         struct cmd_ds_bt_access cmd;
595         int ret = 0;
596
597         lbs_deb_enter(LBS_DEB_CMD);
598
599         memset(&cmd, 0, sizeof(cmd));
600         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
601         cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
602         cmd.id = cpu_to_le32(!!inverted);
603
604         ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
605
606         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
607         return ret;
608 }
609
610 /**
611  * lbs_mesh_bt_get_entry - List an entry in the mesh blinding table
612  *
613  * @priv:       A pointer to &struct lbs_private structure
614  * @id:         The ID of the entry to list
615  * @addr1:      MAC address associated with the table entry
616  *
617  * returns:             0 on success, error on failure
618  */
619 int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
620 {
621         struct cmd_ds_bt_access cmd;
622         int ret = 0;
623
624         lbs_deb_enter(LBS_DEB_CMD);
625
626         BUG_ON(addr1 == NULL);
627
628         memset(&cmd, 0, sizeof(cmd));
629         cmd.hdr.size = cpu_to_le16(sizeof(cmd));
630         cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
631         cmd.id = cpu_to_le32(id);
632
633         ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
634         if (ret == 0)
635                 memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
636
637         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
638         return ret;
639 }
640
641 /**
642  * lbs_cmd_fwt_access - Access the mesh forwarding table
643  *
644  * @priv:       A pointer to &struct lbs_private structure
645  * @cmd_action: The forwarding table action to perform
646  * @cmd:        The pre-filled FWT_ACCESS command
647  *
648  * returns:     0 on success and 'cmd' will be filled with the
649  *              firmware's response
650  */
651 int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
652                         struct cmd_ds_fwt_access *cmd)
653 {
654         int ret;
655
656         lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
657
658         cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
659         cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
660         cmd->hdr.result = 0;
661         cmd->action = cpu_to_le16(cmd_action);
662
663         ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
664
665         lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
666         return 0;
667 }
668
669 int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
670                     struct cmd_ds_mesh_access *cmd)
671 {
672         int ret;
673
674         lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
675
676         cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
677         cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
678         cmd->hdr.result = 0;
679
680         cmd->action = cpu_to_le16(cmd_action);
681
682         ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
683
684         lbs_deb_leave(LBS_DEB_CMD);
685         return ret;
686 }
687
688 static int __lbs_mesh_config_send(struct lbs_private *priv,
689                                   struct cmd_ds_mesh_config *cmd,
690                                   uint16_t action, uint16_t type)
691 {
692         int ret;
693         u16 command = CMD_MESH_CONFIG_OLD;
694
695         lbs_deb_enter(LBS_DEB_CMD);
696
697         /*
698          * Command id is 0xac for v10 FW along with mesh interface
699          * id in bits 14-13-12.
700          */
701         if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
702                 command = CMD_MESH_CONFIG |
703                           (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
704
705         cmd->hdr.command = cpu_to_le16(command);
706         cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
707         cmd->hdr.result = 0;
708
709         cmd->type = cpu_to_le16(type);
710         cmd->action = cpu_to_le16(action);
711
712         ret = lbs_cmd_with_response(priv, command, cmd);
713
714         lbs_deb_leave(LBS_DEB_CMD);
715         return ret;
716 }
717
718 int lbs_mesh_config_send(struct lbs_private *priv,
719                          struct cmd_ds_mesh_config *cmd,
720                          uint16_t action, uint16_t type)
721 {
722         int ret;
723
724         if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
725                 return -EOPNOTSUPP;
726
727         ret = __lbs_mesh_config_send(priv, cmd, action, type);
728         return ret;
729 }
730
731 /* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
732  * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
733  * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
734  * lbs_mesh_config_send.
735  */
736 int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
737 {
738         struct cmd_ds_mesh_config cmd;
739         struct mrvl_meshie *ie;
740         DECLARE_SSID_BUF(ssid);
741
742         memset(&cmd, 0, sizeof(cmd));
743         cmd.channel = cpu_to_le16(chan);
744         ie = (struct mrvl_meshie *)cmd.data;
745
746         switch (action) {
747         case CMD_ACT_MESH_CONFIG_START:
748                 ie->id = WLAN_EID_GENERIC;
749                 ie->val.oui[0] = 0x00;
750                 ie->val.oui[1] = 0x50;
751                 ie->val.oui[2] = 0x43;
752                 ie->val.type = MARVELL_MESH_IE_TYPE;
753                 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
754                 ie->val.version = MARVELL_MESH_IE_VERSION;
755                 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
756                 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
757                 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
758                 ie->val.mesh_id_len = priv->mesh_ssid_len;
759                 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
760                 ie->len = sizeof(struct mrvl_meshie_val) -
761                         IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
762                 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
763                 break;
764         case CMD_ACT_MESH_CONFIG_STOP:
765                 break;
766         default:
767                 return -1;
768         }
769         lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
770                     action, priv->mesh_tlv, chan,
771                     print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
772
773         return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
774 }
775
776
777
778 /***************************************************************************
779  * Persistent configuration support
780  */
781
782 static int mesh_get_default_parameters(struct device *dev,
783                                        struct mrvl_mesh_defaults *defs)
784 {
785         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
786         struct cmd_ds_mesh_config cmd;
787         int ret;
788
789         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
790         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
791                                    CMD_TYPE_MESH_GET_DEFAULTS);
792
793         if (ret)
794                 return -EOPNOTSUPP;
795
796         memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
797
798         return 0;
799 }
800
801 /**
802  * bootflag_get - Get function for sysfs attribute bootflag
803  * @dev: the &struct device
804  * @attr: device attributes
805  * @buf: buffer where data will be returned
806  */
807 static ssize_t bootflag_get(struct device *dev,
808                             struct device_attribute *attr, char *buf)
809 {
810         struct mrvl_mesh_defaults defs;
811         int ret;
812
813         ret = mesh_get_default_parameters(dev, &defs);
814
815         if (ret)
816                 return ret;
817
818         return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
819 }
820
821 /**
822  * bootflag_set - Set function for sysfs attribute bootflag
823  * @dev: the &struct device
824  * @attr: device attributes
825  * @buf: buffer that contains new attribute value
826  * @count: size of buffer
827  */
828 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
829                             const char *buf, size_t count)
830 {
831         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
832         struct cmd_ds_mesh_config cmd;
833         uint32_t datum;
834         int ret;
835
836         memset(&cmd, 0, sizeof(cmd));
837         ret = sscanf(buf, "%d", &datum);
838         if ((ret != 1) || (datum > 1))
839                 return -EINVAL;
840
841         *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
842         cmd.length = cpu_to_le16(sizeof(uint32_t));
843         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
844                                    CMD_TYPE_MESH_SET_BOOTFLAG);
845         if (ret)
846                 return ret;
847
848         return strlen(buf);
849 }
850
851 /**
852  * boottime_get - Get function for sysfs attribute boottime
853  * @dev: the &struct device
854  * @attr: device attributes
855  * @buf: buffer where data will be returned
856  */
857 static ssize_t boottime_get(struct device *dev,
858                             struct device_attribute *attr, char *buf)
859 {
860         struct mrvl_mesh_defaults defs;
861         int ret;
862
863         ret = mesh_get_default_parameters(dev, &defs);
864
865         if (ret)
866                 return ret;
867
868         return snprintf(buf, 12, "%d\n", defs.boottime);
869 }
870
871 /**
872  * boottime_set - Set function for sysfs attribute boottime
873  * @dev: the &struct device
874  * @attr: device attributes
875  * @buf: buffer that contains new attribute value
876  * @count: size of buffer
877  */
878 static ssize_t boottime_set(struct device *dev,
879                 struct device_attribute *attr, const char *buf, size_t count)
880 {
881         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
882         struct cmd_ds_mesh_config cmd;
883         uint32_t datum;
884         int ret;
885
886         memset(&cmd, 0, sizeof(cmd));
887         ret = sscanf(buf, "%d", &datum);
888         if ((ret != 1) || (datum > 255))
889                 return -EINVAL;
890
891         /* A too small boot time will result in the device booting into
892          * standalone (no-host) mode before the host can take control of it,
893          * so the change will be hard to revert.  This may be a desired
894          * feature (e.g to configure a very fast boot time for devices that
895          * will not be attached to a host), but dangerous.  So I'm enforcing a
896          * lower limit of 20 seconds:  remove and recompile the driver if this
897          * does not work for you.
898          */
899         datum = (datum < 20) ? 20 : datum;
900         cmd.data[0] = datum;
901         cmd.length = cpu_to_le16(sizeof(uint8_t));
902         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
903                                    CMD_TYPE_MESH_SET_BOOTTIME);
904         if (ret)
905                 return ret;
906
907         return strlen(buf);
908 }
909
910 /**
911  * channel_get - Get function for sysfs attribute channel
912  * @dev: the &struct device
913  * @attr: device attributes
914  * @buf: buffer where data will be returned
915  */
916 static ssize_t channel_get(struct device *dev,
917                            struct device_attribute *attr, char *buf)
918 {
919         struct mrvl_mesh_defaults defs;
920         int ret;
921
922         ret = mesh_get_default_parameters(dev, &defs);
923
924         if (ret)
925                 return ret;
926
927         return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
928 }
929
930 /**
931  * channel_set - Set function for sysfs attribute channel
932  * @dev: the &struct device
933  * @attr: device attributes
934  * @buf: buffer that contains new attribute value
935  * @count: size of buffer
936  */
937 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
938                            const char *buf, size_t count)
939 {
940         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
941         struct cmd_ds_mesh_config cmd;
942         uint32_t datum;
943         int ret;
944
945         memset(&cmd, 0, sizeof(cmd));
946         ret = sscanf(buf, "%d", &datum);
947         if (ret != 1 || datum < 1 || datum > 11)
948                 return -EINVAL;
949
950         *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
951         cmd.length = cpu_to_le16(sizeof(uint16_t));
952         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
953                                    CMD_TYPE_MESH_SET_DEF_CHANNEL);
954         if (ret)
955                 return ret;
956
957         return strlen(buf);
958 }
959
960 /**
961  * mesh_id_get - Get function for sysfs attribute mesh_id
962  * @dev: the &struct device
963  * @attr: device attributes
964  * @buf: buffer where data will be returned
965  */
966 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
967                            char *buf)
968 {
969         struct mrvl_mesh_defaults defs;
970         int ret;
971
972         ret = mesh_get_default_parameters(dev, &defs);
973
974         if (ret)
975                 return ret;
976
977         if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
978                 dev_err(dev, "inconsistent mesh ID length\n");
979                 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
980         }
981
982         memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
983         buf[defs.meshie.val.mesh_id_len] = '\n';
984         buf[defs.meshie.val.mesh_id_len + 1] = '\0';
985
986         return defs.meshie.val.mesh_id_len + 1;
987 }
988
989 /**
990  * mesh_id_set - Set function for sysfs attribute mesh_id
991  * @dev: the &struct device
992  * @attr: device attributes
993  * @buf: buffer that contains new attribute value
994  * @count: size of buffer
995  */
996 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
997                            const char *buf, size_t count)
998 {
999         struct cmd_ds_mesh_config cmd;
1000         struct mrvl_mesh_defaults defs;
1001         struct mrvl_meshie *ie;
1002         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1003         int len;
1004         int ret;
1005
1006         if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
1007                 return -EINVAL;
1008
1009         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
1010         ie = (struct mrvl_meshie *) &cmd.data[0];
1011
1012         /* fetch all other Information Element parameters */
1013         ret = mesh_get_default_parameters(dev, &defs);
1014
1015         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1016
1017         /* transfer IE elements */
1018         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1019
1020         len = count - 1;
1021         memcpy(ie->val.mesh_id, buf, len);
1022         /* SSID len */
1023         ie->val.mesh_id_len = len;
1024         /* IE len */
1025         ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
1026
1027         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1028                                    CMD_TYPE_MESH_SET_MESH_IE);
1029         if (ret)
1030                 return ret;
1031
1032         return strlen(buf);
1033 }
1034
1035 /**
1036  * protocol_id_get - Get function for sysfs attribute protocol_id
1037  * @dev: the &struct device
1038  * @attr: device attributes
1039  * @buf: buffer where data will be returned
1040  */
1041 static ssize_t protocol_id_get(struct device *dev,
1042                                struct device_attribute *attr, char *buf)
1043 {
1044         struct mrvl_mesh_defaults defs;
1045         int ret;
1046
1047         ret = mesh_get_default_parameters(dev, &defs);
1048
1049         if (ret)
1050                 return ret;
1051
1052         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
1053 }
1054
1055 /**
1056  * protocol_id_set - Set function for sysfs attribute protocol_id
1057  * @dev: the &struct device
1058  * @attr: device attributes
1059  * @buf: buffer that contains new attribute value
1060  * @count: size of buffer
1061  */
1062 static ssize_t protocol_id_set(struct device *dev,
1063                 struct device_attribute *attr, const char *buf, size_t count)
1064 {
1065         struct cmd_ds_mesh_config cmd;
1066         struct mrvl_mesh_defaults defs;
1067         struct mrvl_meshie *ie;
1068         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1069         uint32_t datum;
1070         int ret;
1071
1072         memset(&cmd, 0, sizeof(cmd));
1073         ret = sscanf(buf, "%d", &datum);
1074         if ((ret != 1) || (datum > 255))
1075                 return -EINVAL;
1076
1077         /* fetch all other Information Element parameters */
1078         ret = mesh_get_default_parameters(dev, &defs);
1079
1080         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1081
1082         /* transfer IE elements */
1083         ie = (struct mrvl_meshie *) &cmd.data[0];
1084         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1085         /* update protocol id */
1086         ie->val.active_protocol_id = datum;
1087
1088         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1089                                    CMD_TYPE_MESH_SET_MESH_IE);
1090         if (ret)
1091                 return ret;
1092
1093         return strlen(buf);
1094 }
1095
1096 /**
1097  * metric_id_get - Get function for sysfs attribute metric_id
1098  * @dev: the &struct device
1099  * @attr: device attributes
1100  * @buf: buffer where data will be returned
1101  */
1102 static ssize_t metric_id_get(struct device *dev,
1103                 struct device_attribute *attr, char *buf)
1104 {
1105         struct mrvl_mesh_defaults defs;
1106         int ret;
1107
1108         ret = mesh_get_default_parameters(dev, &defs);
1109
1110         if (ret)
1111                 return ret;
1112
1113         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
1114 }
1115
1116 /**
1117  * metric_id_set - Set function for sysfs attribute metric_id
1118  * @dev: the &struct device
1119  * @attr: device attributes
1120  * @buf: buffer that contains new attribute value
1121  * @count: size of buffer
1122  */
1123 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
1124                              const char *buf, size_t count)
1125 {
1126         struct cmd_ds_mesh_config cmd;
1127         struct mrvl_mesh_defaults defs;
1128         struct mrvl_meshie *ie;
1129         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1130         uint32_t datum;
1131         int ret;
1132
1133         memset(&cmd, 0, sizeof(cmd));
1134         ret = sscanf(buf, "%d", &datum);
1135         if ((ret != 1) || (datum > 255))
1136                 return -EINVAL;
1137
1138         /* fetch all other Information Element parameters */
1139         ret = mesh_get_default_parameters(dev, &defs);
1140
1141         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1142
1143         /* transfer IE elements */
1144         ie = (struct mrvl_meshie *) &cmd.data[0];
1145         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1146         /* update metric id */
1147         ie->val.active_metric_id = datum;
1148
1149         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1150                                    CMD_TYPE_MESH_SET_MESH_IE);
1151         if (ret)
1152                 return ret;
1153
1154         return strlen(buf);
1155 }
1156
1157 /**
1158  * capability_get - Get function for sysfs attribute capability
1159  * @dev: the &struct device
1160  * @attr: device attributes
1161  * @buf: buffer where data will be returned
1162  */
1163 static ssize_t capability_get(struct device *dev,
1164                 struct device_attribute *attr, char *buf)
1165 {
1166         struct mrvl_mesh_defaults defs;
1167         int ret;
1168
1169         ret = mesh_get_default_parameters(dev, &defs);
1170
1171         if (ret)
1172                 return ret;
1173
1174         return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
1175 }
1176
1177 /**
1178  * capability_set - Set function for sysfs attribute capability
1179  * @dev: the &struct device
1180  * @attr: device attributes
1181  * @buf: buffer that contains new attribute value
1182  * @count: size of buffer
1183  */
1184 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
1185                               const char *buf, size_t count)
1186 {
1187         struct cmd_ds_mesh_config cmd;
1188         struct mrvl_mesh_defaults defs;
1189         struct mrvl_meshie *ie;
1190         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1191         uint32_t datum;
1192         int ret;
1193
1194         memset(&cmd, 0, sizeof(cmd));
1195         ret = sscanf(buf, "%d", &datum);
1196         if ((ret != 1) || (datum > 255))
1197                 return -EINVAL;
1198
1199         /* fetch all other Information Element parameters */
1200         ret = mesh_get_default_parameters(dev, &defs);
1201
1202         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1203
1204         /* transfer IE elements */
1205         ie = (struct mrvl_meshie *) &cmd.data[0];
1206         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1207         /* update value */
1208         ie->val.mesh_capability = datum;
1209
1210         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1211                                    CMD_TYPE_MESH_SET_MESH_IE);
1212         if (ret)
1213                 return ret;
1214
1215         return strlen(buf);
1216 }
1217
1218
1219 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
1220 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
1221 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
1222 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
1223 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
1224 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
1225 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
1226
1227 static struct attribute *boot_opts_attrs[] = {
1228         &dev_attr_bootflag.attr,
1229         &dev_attr_boottime.attr,
1230         &dev_attr_channel.attr,
1231         NULL
1232 };
1233
1234 static struct attribute_group boot_opts_group = {
1235         .name = "boot_options",
1236         .attrs = boot_opts_attrs,
1237 };
1238
1239 static struct attribute *mesh_ie_attrs[] = {
1240         &dev_attr_mesh_id.attr,
1241         &dev_attr_protocol_id.attr,
1242         &dev_attr_metric_id.attr,
1243         &dev_attr_capability.attr,
1244         NULL
1245 };
1246
1247 static struct attribute_group mesh_ie_group = {
1248         .name = "mesh_ie",
1249         .attrs = mesh_ie_attrs,
1250 };
1251
1252 void lbs_persist_config_init(struct net_device *dev)
1253 {
1254         int ret;
1255         ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
1256         ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
1257 }
1258
1259 void lbs_persist_config_remove(struct net_device *dev)
1260 {
1261         sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
1262         sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
1263 }
1264
1265
1266
1267 /***************************************************************************
1268  * Ethtool related
1269  */
1270
1271 static const char *mesh_stat_strings[] = {
1272                         "drop_duplicate_bcast",
1273                         "drop_ttl_zero",
1274                         "drop_no_fwd_route",
1275                         "drop_no_buffers",
1276                         "fwded_unicast_cnt",
1277                         "fwded_bcast_cnt",
1278                         "drop_blind_table",
1279                         "tx_failed_cnt"
1280 };
1281
1282 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1283         struct ethtool_stats *stats, uint64_t *data)
1284 {
1285         struct lbs_private *priv = dev->ml_priv;
1286         struct cmd_ds_mesh_access mesh_access;
1287         int ret;
1288
1289         lbs_deb_enter(LBS_DEB_ETHTOOL);
1290
1291         /* Get Mesh Statistics */
1292         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1293
1294         if (ret) {
1295                 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1296                 return;
1297         }
1298
1299         priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1300         priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1301         priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1302         priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1303         priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1304         priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1305         priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1306         priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1307
1308         data[0] = priv->mstats.fwd_drop_rbt;
1309         data[1] = priv->mstats.fwd_drop_ttl;
1310         data[2] = priv->mstats.fwd_drop_noroute;
1311         data[3] = priv->mstats.fwd_drop_nobuf;
1312         data[4] = priv->mstats.fwd_unicast_cnt;
1313         data[5] = priv->mstats.fwd_bcast_cnt;
1314         data[6] = priv->mstats.drop_blind;
1315         data[7] = priv->mstats.tx_failed_cnt;
1316
1317         lbs_deb_enter(LBS_DEB_ETHTOOL);
1318 }
1319
1320 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1321 {
1322         struct lbs_private *priv = dev->ml_priv;
1323
1324         if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1325                 return MESH_STATS_NUM;
1326
1327         return -EOPNOTSUPP;
1328 }
1329
1330 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1331         uint32_t stringset, uint8_t *s)
1332 {
1333         int i;
1334
1335         lbs_deb_enter(LBS_DEB_ETHTOOL);
1336
1337         switch (stringset) {
1338         case ETH_SS_STATS:
1339                 for (i = 0; i < MESH_STATS_NUM; i++) {
1340                         memcpy(s + i * ETH_GSTRING_LEN,
1341                                         mesh_stat_strings[i],
1342                                         ETH_GSTRING_LEN);
1343                 }
1344                 break;
1345         }
1346         lbs_deb_enter(LBS_DEB_ETHTOOL);
1347 }