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