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>
15
/***************************************************************************
20
* Attributes exported through sysfs
24
* @brief Get function for sysfs attribute anycast_mask
26
static ssize_t lbs_anycast_get(struct device *dev,
27
struct device_attribute *attr, char * buf)
29
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
30
struct cmd_ds_mesh_access mesh_access;
33
memset(&mesh_access, 0, sizeof(mesh_access));
35
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
39
return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
43
* @brief Set function for sysfs attribute anycast_mask
45
static ssize_t lbs_anycast_set(struct device *dev,
46
struct device_attribute *attr, const char * buf, size_t count)
48
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
49
struct cmd_ds_mesh_access mesh_access;
53
memset(&mesh_access, 0, sizeof(mesh_access));
54
sscanf(buf, "%x", &datum);
55
mesh_access.data[0] = cpu_to_le32(datum);
57
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
65
* @brief Get function for sysfs attribute prb_rsp_limit
67
static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
68
struct device_attribute *attr, char *buf)
70
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
71
struct cmd_ds_mesh_access mesh_access;
75
memset(&mesh_access, 0, sizeof(mesh_access));
76
mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
78
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
83
retry_limit = le32_to_cpu(mesh_access.data[1]);
84
return snprintf(buf, 10, "%d\n", retry_limit);
88
* @brief Set function for sysfs attribute prb_rsp_limit
90
static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
91
struct device_attribute *attr, const char *buf, size_t count)
93
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
94
struct cmd_ds_mesh_access mesh_access;
96
unsigned long retry_limit;
98
memset(&mesh_access, 0, sizeof(mesh_access));
99
mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
101
if (!strict_strtoul(buf, 10, &retry_limit))
103
if (retry_limit > 15)
106
mesh_access.data[1] = cpu_to_le32(retry_limit);
108
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
117
* Get function for sysfs attribute mesh
119
static ssize_t lbs_mesh_get(struct device *dev,
120
struct device_attribute *attr, char * buf)
122
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
123
return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
127
* Set function for sysfs attribute mesh
129
static ssize_t lbs_mesh_set(struct device *dev,
130
struct device_attribute *attr, const char * buf, size_t count)
132
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
134
int ret, action = CMD_ACT_MESH_CONFIG_STOP;
136
sscanf(buf, "%x", &enable);
138
if (enable == !!priv->mesh_dev)
141
action = CMD_ACT_MESH_CONFIG_START;
142
ret = lbs_mesh_config(priv, action, priv->channel);
149
lbs_remove_mesh(priv);
155
* lbs_mesh attribute to be exported per ethX interface
156
* through sysfs (/sys/class/net/ethX/lbs_mesh)
158
static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
161
* anycast_mask attribute to be exported per mshX interface
162
* through sysfs (/sys/class/net/mshX/anycast_mask)
164
static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
167
* prb_rsp_limit attribute to be exported per mshX interface
168
* through sysfs (/sys/class/net/mshX/prb_rsp_limit)
170
static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
171
lbs_prb_rsp_limit_set);
173
static struct attribute *lbs_mesh_sysfs_entries[] = {
174
&dev_attr_anycast_mask.attr,
175
&dev_attr_prb_rsp_limit.attr,
179
static struct attribute_group lbs_mesh_attr_group = {
180
.attrs = lbs_mesh_sysfs_entries,
185
/***************************************************************************
186
* Initializing and starting, stopping mesh
190
* Check mesh FW version and appropriately send the mesh start
193
int lbs_init_mesh(struct lbs_private *priv)
195
struct net_device *dev = priv->dev;
198
lbs_deb_enter(LBS_DEB_MESH);
200
priv->mesh_connect_status = LBS_DISCONNECTED;
202
/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
203
/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
204
/* 5.110.22 have mesh command with 0xa3 command id */
205
/* 10.0.0.p0 FW brings in mesh config command with different id */
206
/* Check FW version MSB and initialize mesh_fw_ver */
207
if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
208
/* Enable mesh, if supported, and work out which TLV it uses.
209
0x100 + 291 is an unofficial value used in 5.110.20.pXX
210
0x100 + 37 is the official value used in 5.110.21.pXX
211
but we check them in that order because 20.pXX doesn't
212
give an error -- it just silently fails. */
214
/* 5.110.20.pXX firmware will fail the command if the channel
215
doesn't match the existing channel. But only if the TLV
216
is correct. If the channel is wrong, _BOTH_ versions will
217
give an error to 0x100+291, and allow 0x100+37 to succeed.
218
It's just that 5.110.20.pXX will not have done anything
221
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
222
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
224
priv->mesh_tlv = TLV_TYPE_MESH_ID;
225
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
230
if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
231
(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
232
/* 10.0.0.pXX new firmwares should succeed with TLV
233
* 0x100+37; Do not invoke command with old TLV.
235
priv->mesh_tlv = TLV_TYPE_MESH_ID;
236
if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
242
if (priv->mesh_tlv) {
243
sprintf(priv->mesh_ssid, "mesh");
244
priv->mesh_ssid_len = 4;
248
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
249
lbs_pr_err("cannot register lbs_mesh attribute\n");
254
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
259
int lbs_deinit_mesh(struct lbs_private *priv)
261
struct net_device *dev = priv->dev;
264
lbs_deb_enter(LBS_DEB_MESH);
266
if (priv->mesh_tlv) {
267
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
271
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
277
* @brief This function closes the mshX interface
279
* @param dev A pointer to net_device structure
282
static int lbs_mesh_stop(struct net_device *dev)
284
struct lbs_private *priv = dev->ml_priv;
286
lbs_deb_enter(LBS_DEB_MESH);
287
spin_lock_irq(&priv->driver_lock);
290
priv->mesh_connect_status = LBS_DISCONNECTED;
292
netif_stop_queue(dev);
293
netif_carrier_off(dev);
295
spin_unlock_irq(&priv->driver_lock);
297
schedule_work(&priv->mcast_work);
299
lbs_deb_leave(LBS_DEB_MESH);
304
* @brief This function opens the mshX interface
306
* @param dev A pointer to net_device structure
307
* @return 0 or -EBUSY if monitor mode active
309
static int lbs_mesh_dev_open(struct net_device *dev)
311
struct lbs_private *priv = dev->ml_priv;
314
lbs_deb_enter(LBS_DEB_NET);
316
spin_lock_irq(&priv->driver_lock);
318
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
324
priv->mesh_connect_status = LBS_CONNECTED;
325
netif_carrier_on(dev);
327
if (!priv->tx_pending_len)
328
netif_wake_queue(dev);
331
spin_unlock_irq(&priv->driver_lock);
332
lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
336
static const struct net_device_ops mesh_netdev_ops = {
337
.ndo_open = lbs_mesh_dev_open,
338
.ndo_stop = lbs_mesh_stop,
339
.ndo_start_xmit = lbs_hard_start_xmit,
340
.ndo_set_mac_address = lbs_set_mac_address,
341
.ndo_set_multicast_list = lbs_set_multicast_list,
345
* @brief This function adds mshX interface
347
* @param priv A pointer to the struct lbs_private structure
348
* @return 0 if successful, -X otherwise
350
int lbs_add_mesh(struct lbs_private *priv)
352
struct net_device *mesh_dev = NULL;
355
lbs_deb_enter(LBS_DEB_MESH);
357
/* Allocate a virtual mesh device */
358
mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
360
lbs_deb_mesh("init mshX device failed\n");
364
mesh_dev->ml_priv = priv;
365
priv->mesh_dev = mesh_dev;
367
netdev_attach_ops(mesh_dev, &mesh_netdev_ops);
368
mesh_dev->ethtool_ops = &lbs_ethtool_ops;
369
memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
371
SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
373
mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
374
/* Register virtual mesh interface */
375
ret = register_netdev(mesh_dev);
377
lbs_pr_err("cannot register mshX virtual interface\n");
381
ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
385
lbs_persist_config_init(mesh_dev);
387
/* Everything successful */
392
unregister_netdev(mesh_dev);
395
free_netdev(mesh_dev);
398
lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
402
void lbs_remove_mesh(struct lbs_private *priv)
404
struct net_device *mesh_dev;
406
mesh_dev = priv->mesh_dev;
410
lbs_deb_enter(LBS_DEB_MESH);
411
netif_stop_queue(mesh_dev);
412
netif_carrier_off(mesh_dev);
413
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
414
lbs_persist_config_remove(mesh_dev);
415
unregister_netdev(mesh_dev);
416
priv->mesh_dev = NULL;
417
free_netdev(mesh_dev);
418
lbs_deb_leave(LBS_DEB_MESH);
423
/***************************************************************************
424
* Sending and receiving
426
struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
427
struct net_device *dev, struct rxpd *rxpd)
429
if (priv->mesh_dev) {
430
if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
431
if (rxpd->rx_control & RxPD_MESH_FRAME)
432
dev = priv->mesh_dev;
433
} else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
434
if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
435
dev = priv->mesh_dev;
442
void lbs_mesh_set_txpd(struct lbs_private *priv,
443
struct net_device *dev, struct txpd *txpd)
445
if (dev == priv->mesh_dev) {
446
if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
447
txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
448
else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
449
txpd->u.bss.bss_num = MESH_IFACE_ID;
454
/***************************************************************************
455
* Mesh command handling
459
* @brief Add or delete Mesh Blinding Table entries
461
* @param priv A pointer to struct lbs_private structure
462
* @param add TRUE to add the entry, FALSE to delete it
463
* @param addr1 Destination address to blind or unblind
465
* @return 0 on success, error on failure
467
int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
469
struct cmd_ds_bt_access cmd;
472
lbs_deb_enter(LBS_DEB_CMD);
474
BUG_ON(addr1 == NULL);
476
memset(&cmd, 0, sizeof(cmd));
477
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
478
memcpy(cmd.addr1, addr1, ETH_ALEN);
480
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_ADD);
481
lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
484
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_DEL);
485
lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
489
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
491
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
496
* @brief Reset/clear the mesh blinding table
498
* @param priv A pointer to struct lbs_private structure
500
* @return 0 on success, error on failure
502
int lbs_mesh_bt_reset(struct lbs_private *priv)
504
struct cmd_ds_bt_access cmd;
507
lbs_deb_enter(LBS_DEB_CMD);
509
memset(&cmd, 0, sizeof(cmd));
510
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
511
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_RESET);
513
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
515
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
520
* @brief Gets the inverted status of the mesh blinding table
522
* Normally the firmware "blinds" or ignores traffic from mesh nodes in the
523
* table, but an inverted table allows *only* traffic from nodes listed in
526
* @param priv A pointer to struct lbs_private structure
527
* @param invert On success, TRUE if the blinding table is inverted,
528
* FALSE if it is not inverted
530
* @return 0 on success, error on failure
532
int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
534
struct cmd_ds_bt_access cmd;
537
lbs_deb_enter(LBS_DEB_CMD);
539
BUG_ON(inverted == NULL);
541
memset(&cmd, 0, sizeof(cmd));
542
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
543
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_GET_INVERT);
545
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
547
*inverted = !!cmd.id;
549
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
554
* @brief Sets the inverted status of the mesh blinding table
556
* Normally the firmware "blinds" or ignores traffic from mesh nodes in the
557
* table, but an inverted table allows *only* traffic from nodes listed in
560
* @param priv A pointer to struct lbs_private structure
561
* @param invert TRUE to invert the blinding table (only traffic from
562
* listed nodes allowed), FALSE to return it
563
* to normal state (listed nodes ignored)
565
* @return 0 on success, error on failure
567
int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
569
struct cmd_ds_bt_access cmd;
572
lbs_deb_enter(LBS_DEB_CMD);
574
memset(&cmd, 0, sizeof(cmd));
575
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
576
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
577
cmd.id = cpu_to_le32(!!inverted);
579
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
581
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
586
* @brief List an entry in the mesh blinding table
588
* @param priv A pointer to struct lbs_private structure
589
* @param id The ID of the entry to list
590
* @param addr1 MAC address associated with the table entry
592
* @return 0 on success, error on failure
594
int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
596
struct cmd_ds_bt_access cmd;
599
lbs_deb_enter(LBS_DEB_CMD);
601
BUG_ON(addr1 == NULL);
603
memset(&cmd, 0, sizeof(cmd));
604
cmd.hdr.size = cpu_to_le16(sizeof(cmd));
605
cmd.action = cpu_to_le16(CMD_ACT_BT_ACCESS_SET_INVERT);
606
cmd.id = cpu_to_le32(id);
608
ret = lbs_cmd_with_response(priv, CMD_BT_ACCESS, &cmd);
610
memcpy(addr1, cmd.addr1, sizeof(cmd.addr1));
612
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
617
* @brief Access the mesh forwarding table
619
* @param priv A pointer to struct lbs_private structure
620
* @param cmd_action The forwarding table action to perform
621
* @param cmd The pre-filled FWT_ACCESS command
623
* @return 0 on success and 'cmd' will be filled with the
624
* firmware's response
626
int lbs_cmd_fwt_access(struct lbs_private *priv, u16 cmd_action,
627
struct cmd_ds_fwt_access *cmd)
631
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
633
cmd->hdr.command = cpu_to_le16(CMD_FWT_ACCESS);
634
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access));
636
cmd->action = cpu_to_le16(cmd_action);
638
ret = lbs_cmd_with_response(priv, CMD_FWT_ACCESS, cmd);
640
lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
644
int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
645
struct cmd_ds_mesh_access *cmd)
649
lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
651
cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
652
cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
655
cmd->action = cpu_to_le16(cmd_action);
657
ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
659
lbs_deb_leave(LBS_DEB_CMD);
663
static int __lbs_mesh_config_send(struct lbs_private *priv,
664
struct cmd_ds_mesh_config *cmd,
665
uint16_t action, uint16_t type)
668
u16 command = CMD_MESH_CONFIG_OLD;
670
lbs_deb_enter(LBS_DEB_CMD);
673
* Command id is 0xac for v10 FW along with mesh interface
674
* id in bits 14-13-12.
676
if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
677
command = CMD_MESH_CONFIG |
678
(MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
680
cmd->hdr.command = cpu_to_le16(command);
681
cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
684
cmd->type = cpu_to_le16(type);
685
cmd->action = cpu_to_le16(action);
687
ret = lbs_cmd_with_response(priv, command, cmd);
689
lbs_deb_leave(LBS_DEB_CMD);
693
int lbs_mesh_config_send(struct lbs_private *priv,
694
struct cmd_ds_mesh_config *cmd,
695
uint16_t action, uint16_t type)
699
if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
702
ret = __lbs_mesh_config_send(priv, cmd, action, type);
706
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the
707
* START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
708
* are all handled by preparing a struct cmd_ds_mesh_config and passing it to
709
* lbs_mesh_config_send.
711
int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
713
struct cmd_ds_mesh_config cmd;
714
struct mrvl_meshie *ie;
715
DECLARE_SSID_BUF(ssid);
717
memset(&cmd, 0, sizeof(cmd));
718
cmd.channel = cpu_to_le16(chan);
719
ie = (struct mrvl_meshie *)cmd.data;
722
case CMD_ACT_MESH_CONFIG_START:
723
ie->id = WLAN_EID_GENERIC;
724
ie->val.oui[0] = 0x00;
725
ie->val.oui[1] = 0x50;
726
ie->val.oui[2] = 0x43;
727
ie->val.type = MARVELL_MESH_IE_TYPE;
728
ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
729
ie->val.version = MARVELL_MESH_IE_VERSION;
730
ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
731
ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
732
ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
733
ie->val.mesh_id_len = priv->mesh_ssid_len;
734
memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
735
ie->len = sizeof(struct mrvl_meshie_val) -
736
IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
737
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
739
case CMD_ACT_MESH_CONFIG_STOP:
744
lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
745
action, priv->mesh_tlv, chan,
746
print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
748
return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
753
/***************************************************************************
754
* Persistent configuration support
757
static int mesh_get_default_parameters(struct device *dev,
758
struct mrvl_mesh_defaults *defs)
760
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
761
struct cmd_ds_mesh_config cmd;
764
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
765
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
766
CMD_TYPE_MESH_GET_DEFAULTS);
771
memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
777
* @brief Get function for sysfs attribute bootflag
779
static ssize_t bootflag_get(struct device *dev,
780
struct device_attribute *attr, char *buf)
782
struct mrvl_mesh_defaults defs;
785
ret = mesh_get_default_parameters(dev, &defs);
790
return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
794
* @brief Set function for sysfs attribute bootflag
796
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
797
const char *buf, size_t count)
799
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
800
struct cmd_ds_mesh_config cmd;
804
memset(&cmd, 0, sizeof(cmd));
805
ret = sscanf(buf, "%d", &datum);
806
if ((ret != 1) || (datum > 1))
809
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
810
cmd.length = cpu_to_le16(sizeof(uint32_t));
811
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
812
CMD_TYPE_MESH_SET_BOOTFLAG);
820
* @brief Get function for sysfs attribute boottime
822
static ssize_t boottime_get(struct device *dev,
823
struct device_attribute *attr, char *buf)
825
struct mrvl_mesh_defaults defs;
828
ret = mesh_get_default_parameters(dev, &defs);
833
return snprintf(buf, 12, "%d\n", defs.boottime);
837
* @brief Set function for sysfs attribute boottime
839
static ssize_t boottime_set(struct device *dev,
840
struct device_attribute *attr, const char *buf, size_t count)
842
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
843
struct cmd_ds_mesh_config cmd;
847
memset(&cmd, 0, sizeof(cmd));
848
ret = sscanf(buf, "%d", &datum);
849
if ((ret != 1) || (datum > 255))
852
/* A too small boot time will result in the device booting into
853
* standalone (no-host) mode before the host can take control of it,
854
* so the change will be hard to revert. This may be a desired
855
* feature (e.g to configure a very fast boot time for devices that
856
* will not be attached to a host), but dangerous. So I'm enforcing a
857
* lower limit of 20 seconds: remove and recompile the driver if this
858
* does not work for you.
860
datum = (datum < 20) ? 20 : datum;
862
cmd.length = cpu_to_le16(sizeof(uint8_t));
863
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
864
CMD_TYPE_MESH_SET_BOOTTIME);
872
* @brief Get function for sysfs attribute channel
874
static ssize_t channel_get(struct device *dev,
875
struct device_attribute *attr, char *buf)
877
struct mrvl_mesh_defaults defs;
880
ret = mesh_get_default_parameters(dev, &defs);
885
return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
889
* @brief Set function for sysfs attribute channel
891
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
892
const char *buf, size_t count)
894
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
895
struct cmd_ds_mesh_config cmd;
899
memset(&cmd, 0, sizeof(cmd));
900
ret = sscanf(buf, "%d", &datum);
901
if (ret != 1 || datum < 1 || datum > 11)
904
*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
905
cmd.length = cpu_to_le16(sizeof(uint16_t));
906
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
907
CMD_TYPE_MESH_SET_DEF_CHANNEL);
915
* @brief Get function for sysfs attribute mesh_id
917
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
920
struct mrvl_mesh_defaults defs;
923
ret = mesh_get_default_parameters(dev, &defs);
928
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
929
lbs_pr_err("inconsistent mesh ID length");
930
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
933
memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
934
buf[defs.meshie.val.mesh_id_len] = '\n';
935
buf[defs.meshie.val.mesh_id_len + 1] = '\0';
937
return defs.meshie.val.mesh_id_len + 1;
941
* @brief Set function for sysfs attribute mesh_id
943
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
944
const char *buf, size_t count)
946
struct cmd_ds_mesh_config cmd;
947
struct mrvl_mesh_defaults defs;
948
struct mrvl_meshie *ie;
949
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
953
if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
956
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
957
ie = (struct mrvl_meshie *) &cmd.data[0];
959
/* fetch all other Information Element parameters */
960
ret = mesh_get_default_parameters(dev, &defs);
962
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
964
/* transfer IE elements */
965
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
968
memcpy(ie->val.mesh_id, buf, len);
970
ie->val.mesh_id_len = len;
972
ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
974
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
975
CMD_TYPE_MESH_SET_MESH_IE);
983
* @brief Get function for sysfs attribute protocol_id
985
static ssize_t protocol_id_get(struct device *dev,
986
struct device_attribute *attr, char *buf)
988
struct mrvl_mesh_defaults defs;
991
ret = mesh_get_default_parameters(dev, &defs);
996
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
1000
* @brief Set function for sysfs attribute protocol_id
1002
static ssize_t protocol_id_set(struct device *dev,
1003
struct device_attribute *attr, const char *buf, size_t count)
1005
struct cmd_ds_mesh_config cmd;
1006
struct mrvl_mesh_defaults defs;
1007
struct mrvl_meshie *ie;
1008
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1012
memset(&cmd, 0, sizeof(cmd));
1013
ret = sscanf(buf, "%d", &datum);
1014
if ((ret != 1) || (datum > 255))
1017
/* fetch all other Information Element parameters */
1018
ret = mesh_get_default_parameters(dev, &defs);
1020
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1022
/* transfer IE elements */
1023
ie = (struct mrvl_meshie *) &cmd.data[0];
1024
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1025
/* update protocol id */
1026
ie->val.active_protocol_id = datum;
1028
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1029
CMD_TYPE_MESH_SET_MESH_IE);
1037
* @brief Get function for sysfs attribute metric_id
1039
static ssize_t metric_id_get(struct device *dev,
1040
struct device_attribute *attr, char *buf)
1042
struct mrvl_mesh_defaults defs;
1045
ret = mesh_get_default_parameters(dev, &defs);
1050
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
1054
* @brief Set function for sysfs attribute metric_id
1056
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
1057
const char *buf, size_t count)
1059
struct cmd_ds_mesh_config cmd;
1060
struct mrvl_mesh_defaults defs;
1061
struct mrvl_meshie *ie;
1062
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1066
memset(&cmd, 0, sizeof(cmd));
1067
ret = sscanf(buf, "%d", &datum);
1068
if ((ret != 1) || (datum > 255))
1071
/* fetch all other Information Element parameters */
1072
ret = mesh_get_default_parameters(dev, &defs);
1074
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1076
/* transfer IE elements */
1077
ie = (struct mrvl_meshie *) &cmd.data[0];
1078
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1079
/* update metric id */
1080
ie->val.active_metric_id = datum;
1082
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1083
CMD_TYPE_MESH_SET_MESH_IE);
1091
* @brief Get function for sysfs attribute capability
1093
static ssize_t capability_get(struct device *dev,
1094
struct device_attribute *attr, char *buf)
1096
struct mrvl_mesh_defaults defs;
1099
ret = mesh_get_default_parameters(dev, &defs);
1104
return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
1108
* @brief Set function for sysfs attribute capability
1110
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
1111
const char *buf, size_t count)
1113
struct cmd_ds_mesh_config cmd;
1114
struct mrvl_mesh_defaults defs;
1115
struct mrvl_meshie *ie;
1116
struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1120
memset(&cmd, 0, sizeof(cmd));
1121
ret = sscanf(buf, "%d", &datum);
1122
if ((ret != 1) || (datum > 255))
1125
/* fetch all other Information Element parameters */
1126
ret = mesh_get_default_parameters(dev, &defs);
1128
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1130
/* transfer IE elements */
1131
ie = (struct mrvl_meshie *) &cmd.data[0];
1132
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1134
ie->val.mesh_capability = datum;
1136
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1137
CMD_TYPE_MESH_SET_MESH_IE);
1145
static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
1146
static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
1147
static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
1148
static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
1149
static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
1150
static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
1151
static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
1153
static struct attribute *boot_opts_attrs[] = {
1154
&dev_attr_bootflag.attr,
1155
&dev_attr_boottime.attr,
1156
&dev_attr_channel.attr,
1160
static struct attribute_group boot_opts_group = {
1161
.name = "boot_options",
1162
.attrs = boot_opts_attrs,
1165
static struct attribute *mesh_ie_attrs[] = {
1166
&dev_attr_mesh_id.attr,
1167
&dev_attr_protocol_id.attr,
1168
&dev_attr_metric_id.attr,
1169
&dev_attr_capability.attr,
1173
static struct attribute_group mesh_ie_group = {
1175
.attrs = mesh_ie_attrs,
1178
void lbs_persist_config_init(struct net_device *dev)
1181
ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
1182
ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
1185
void lbs_persist_config_remove(struct net_device *dev)
1187
sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
1188
sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
1193
/***************************************************************************
1197
static const char *mesh_stat_strings[] = {
1198
"drop_duplicate_bcast",
1200
"drop_no_fwd_route",
1202
"fwded_unicast_cnt",
1208
void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1209
struct ethtool_stats *stats, uint64_t *data)
1211
struct lbs_private *priv = dev->ml_priv;
1212
struct cmd_ds_mesh_access mesh_access;
1215
lbs_deb_enter(LBS_DEB_ETHTOOL);
1217
/* Get Mesh Statistics */
1218
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1221
memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1225
priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1226
priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1227
priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1228
priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1229
priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1230
priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1231
priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1232
priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1234
data[0] = priv->mstats.fwd_drop_rbt;
1235
data[1] = priv->mstats.fwd_drop_ttl;
1236
data[2] = priv->mstats.fwd_drop_noroute;
1237
data[3] = priv->mstats.fwd_drop_nobuf;
1238
data[4] = priv->mstats.fwd_unicast_cnt;
1239
data[5] = priv->mstats.fwd_bcast_cnt;
1240
data[6] = priv->mstats.drop_blind;
1241
data[7] = priv->mstats.tx_failed_cnt;
1243
lbs_deb_enter(LBS_DEB_ETHTOOL);
1246
int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1248
struct lbs_private *priv = dev->ml_priv;
1250
if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1251
return MESH_STATS_NUM;
1256
void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1257
uint32_t stringset, uint8_t *s)
1261
lbs_deb_enter(LBS_DEB_ETHTOOL);
1263
switch (stringset) {
1265
for (i = 0; i < MESH_STATS_NUM; i++) {
1266
memcpy(s + i * ETH_GSTRING_LEN,
1267
mesh_stat_strings[i],
1272
lbs_deb_enter(LBS_DEB_ETHTOOL);