1 #include <linux/moduleparam.h>
2 #include <linux/delay.h>
3 #include <linux/etherdevice.h>
4 #include <linux/netdevice.h>
5 #include <linux/if_arp.h>
6 #include <linux/kthread.h>
7 #include <linux/kfifo.h>
14 /***************************************************************************
19 * Attributes exported through sysfs
23 * @brief Get function for sysfs attribute anycast_mask
25 static ssize_t lbs_anycast_get(struct device *dev,
26 struct device_attribute *attr, char * buf)
28 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
29 struct cmd_ds_mesh_access mesh_access;
32 memset(&mesh_access, 0, sizeof(mesh_access));
34 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
38 return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
42 * @brief Set function for sysfs attribute anycast_mask
44 static ssize_t lbs_anycast_set(struct device *dev,
45 struct device_attribute *attr, const char * buf, size_t count)
47 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
48 struct cmd_ds_mesh_access mesh_access;
52 memset(&mesh_access, 0, sizeof(mesh_access));
53 sscanf(buf, "%x", &datum);
54 mesh_access.data[0] = cpu_to_le32(datum);
56 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
64 * @brief Get function for sysfs attribute prb_rsp_limit
66 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
67 struct device_attribute *attr, char *buf)
69 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
70 struct cmd_ds_mesh_access mesh_access;
74 memset(&mesh_access, 0, sizeof(mesh_access));
75 mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
77 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
82 retry_limit = le32_to_cpu(mesh_access.data[1]);
83 return snprintf(buf, 10, "%d\n", retry_limit);
87 * @brief Set function for sysfs attribute prb_rsp_limit
89 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
90 struct device_attribute *attr, const char *buf, size_t count)
92 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
93 struct cmd_ds_mesh_access mesh_access;
95 unsigned long retry_limit;
97 memset(&mesh_access, 0, sizeof(mesh_access));
98 mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
100 if (!strict_strtoul(buf, 10, &retry_limit))
102 if (retry_limit > 15)
105 mesh_access.data[1] = cpu_to_le32(retry_limit);
107 ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
116 * Get function for sysfs attribute mesh
118 static ssize_t lbs_mesh_get(struct device *dev,
119 struct device_attribute *attr, char * buf)
121 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
122 return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
126 * Set function for sysfs attribute mesh
128 static ssize_t lbs_mesh_set(struct device *dev,
129 struct device_attribute *attr, const char * buf, size_t count)
131 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
133 int ret, action = CMD_ACT_MESH_CONFIG_STOP;
135 sscanf(buf, "%x", &enable);
137 if (enable == !!priv->mesh_dev)
140 action = CMD_ACT_MESH_CONFIG_START;
141 ret = lbs_mesh_config(priv, action, priv->channel);
148 lbs_remove_mesh(priv);
154 * lbs_mesh attribute to be exported per ethX interface
155 * through sysfs (/sys/class/net/ethX/lbs_mesh)
157 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
160 * anycast_mask attribute to be exported per mshX interface
161 * through sysfs (/sys/class/net/mshX/anycast_mask)
163 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
166 * prb_rsp_limit attribute to be exported per mshX interface
167 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
169 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
170 lbs_prb_rsp_limit_set);
172 static struct attribute *lbs_mesh_sysfs_entries[] = {
173 &dev_attr_anycast_mask.attr,
174 &dev_attr_prb_rsp_limit.attr,
178 static struct attribute_group lbs_mesh_attr_group = {
179 .attrs = lbs_mesh_sysfs_entries,
184 /***************************************************************************
185 * Initializing and starting, stopping mesh
189 * Check mesh FW version and appropriately send the mesh start
192 int lbs_init_mesh(struct lbs_private *priv)
194 struct net_device *dev = priv->dev;
197 lbs_deb_enter(LBS_DEB_MESH);
199 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
200 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
201 /* 5.110.22 have mesh command with 0xa3 command id */
202 /* 10.0.0.p0 FW brings in mesh config command with different id */
203 /* Check FW version MSB and initialize mesh_fw_ver */
204 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
205 /* Enable mesh, if supported, and work out which TLV it uses.
206 0x100 + 291 is an unofficial value used in 5.110.20.pXX
207 0x100 + 37 is the official value used in 5.110.21.pXX
208 but we check them in that order because 20.pXX doesn't
209 give an error -- it just silently fails. */
211 /* 5.110.20.pXX firmware will fail the command if the channel
212 doesn't match the existing channel. But only if the TLV
213 is correct. If the channel is wrong, _BOTH_ versions will
214 give an error to 0x100+291, and allow 0x100+37 to succeed.
215 It's just that 5.110.20.pXX will not have done anything
218 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
219 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
221 priv->mesh_tlv = TLV_TYPE_MESH_ID;
222 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
227 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
228 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
229 /* 10.0.0.pXX new firmwares should succeed with TLV
230 * 0x100+37; Do not invoke command with old TLV.
232 priv->mesh_tlv = TLV_TYPE_MESH_ID;
233 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
239 if (priv->mesh_tlv) {
240 sprintf(priv->mesh_ssid, "mesh");
241 priv->mesh_ssid_len = 4;
245 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
246 lbs_pr_err("cannot register lbs_mesh attribute\n");
251 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
256 int lbs_deinit_mesh(struct lbs_private *priv)
258 struct net_device *dev = priv->dev;
261 lbs_deb_enter(LBS_DEB_MESH);
263 if (priv->mesh_tlv) {
264 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
268 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
274 * @brief This function closes the mshX interface
276 * @param dev A pointer to net_device structure
279 static int lbs_mesh_stop(struct net_device *dev)
281 struct lbs_private *priv = dev->ml_priv;
283 lbs_deb_enter(LBS_DEB_MESH);
284 spin_lock_irq(&priv->driver_lock);
287 priv->mesh_connect_status = LBS_DISCONNECTED;
289 netif_stop_queue(dev);
290 netif_carrier_off(dev);
292 spin_unlock_irq(&priv->driver_lock);
294 schedule_work(&priv->mcast_work);
296 lbs_deb_leave(LBS_DEB_MESH);
301 * @brief This function opens the mshX interface
303 * @param dev A pointer to net_device structure
304 * @return 0 or -EBUSY if monitor mode active
306 static int lbs_mesh_dev_open(struct net_device *dev)
308 struct lbs_private *priv = dev->ml_priv;
311 lbs_deb_enter(LBS_DEB_NET);
313 spin_lock_irq(&priv->driver_lock);
315 if (priv->monitormode) {
321 priv->mesh_connect_status = LBS_CONNECTED;
322 netif_carrier_on(dev);
324 if (!priv->tx_pending_len)
325 netif_wake_queue(dev);
328 spin_unlock_irq(&priv->driver_lock);
329 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
333 static const struct net_device_ops mesh_netdev_ops = {
334 .ndo_open = lbs_mesh_dev_open,
335 .ndo_stop = lbs_mesh_stop,
336 .ndo_start_xmit = lbs_hard_start_xmit,
337 .ndo_set_mac_address = lbs_set_mac_address,
338 .ndo_set_multicast_list = lbs_set_multicast_list,
342 * @brief This function adds mshX interface
344 * @param priv A pointer to the struct lbs_private structure
345 * @return 0 if successful, -X otherwise
347 int lbs_add_mesh(struct lbs_private *priv)
349 struct net_device *mesh_dev = NULL;
352 lbs_deb_enter(LBS_DEB_MESH);
354 /* Allocate a virtual mesh device */
355 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
357 lbs_deb_mesh("init mshX device failed\n");
361 mesh_dev->ml_priv = priv;
362 priv->mesh_dev = mesh_dev;
364 mesh_dev->netdev_ops = &mesh_netdev_ops;
365 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
366 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
367 sizeof(priv->dev->dev_addr));
369 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
372 mesh_dev->wireless_handlers = &mesh_handler_def;
374 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
375 /* Register virtual mesh interface */
376 ret = register_netdev(mesh_dev);
378 lbs_pr_err("cannot register mshX virtual interface\n");
382 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
386 lbs_persist_config_init(mesh_dev);
388 /* Everything successful */
393 unregister_netdev(mesh_dev);
396 free_netdev(mesh_dev);
399 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
403 void lbs_remove_mesh(struct lbs_private *priv)
405 struct net_device *mesh_dev;
407 mesh_dev = priv->mesh_dev;
411 lbs_deb_enter(LBS_DEB_MESH);
412 netif_stop_queue(mesh_dev);
413 netif_carrier_off(mesh_dev);
414 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
415 lbs_persist_config_remove(mesh_dev);
416 unregister_netdev(mesh_dev);
417 priv->mesh_dev = NULL;
418 free_netdev(mesh_dev);
419 lbs_deb_leave(LBS_DEB_MESH);
424 /***************************************************************************
425 * Sending and receiving
427 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
428 struct net_device *dev, struct rxpd *rxpd)
430 if (priv->mesh_dev) {
431 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
432 if (rxpd->rx_control & RxPD_MESH_FRAME)
433 dev = priv->mesh_dev;
434 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
435 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
436 dev = priv->mesh_dev;
443 void lbs_mesh_set_txpd(struct lbs_private *priv,
444 struct net_device *dev, struct txpd *txpd)
446 if (dev == priv->mesh_dev) {
447 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
448 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
449 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
450 txpd->u.bss.bss_num = MESH_IFACE_ID;
455 /***************************************************************************
456 * Mesh command handling
459 int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
460 u16 cmd_action, void *pdata_buf)
462 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
463 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
465 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
466 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
467 sizeof(struct cmd_header));
469 bt_access->action = cpu_to_le16(cmd_action);
471 switch (cmd_action) {
472 case CMD_ACT_BT_ACCESS_ADD:
473 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
474 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
475 bt_access->addr1, 6);
477 case CMD_ACT_BT_ACCESS_DEL:
478 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
479 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
480 bt_access->addr1, 6);
482 case CMD_ACT_BT_ACCESS_LIST:
483 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
485 case CMD_ACT_BT_ACCESS_RESET:
487 case CMD_ACT_BT_ACCESS_SET_INVERT:
488 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
490 case CMD_ACT_BT_ACCESS_GET_INVERT:
495 lbs_deb_leave(LBS_DEB_CMD);
499 int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
500 u16 cmd_action, void *pdata_buf)
502 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
503 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
505 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
506 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
507 sizeof(struct cmd_header));
511 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
513 memset(fwt_access, 0, sizeof(*fwt_access));
515 fwt_access->action = cpu_to_le16(cmd_action);
517 lbs_deb_leave(LBS_DEB_CMD);
521 int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
522 struct cmd_ds_mesh_access *cmd)
526 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
528 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
529 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
532 cmd->action = cpu_to_le16(cmd_action);
534 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
536 lbs_deb_leave(LBS_DEB_CMD);
540 static int __lbs_mesh_config_send(struct lbs_private *priv,
541 struct cmd_ds_mesh_config *cmd,
542 uint16_t action, uint16_t type)
545 u16 command = CMD_MESH_CONFIG_OLD;
547 lbs_deb_enter(LBS_DEB_CMD);
550 * Command id is 0xac for v10 FW along with mesh interface
551 * id in bits 14-13-12.
553 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
554 command = CMD_MESH_CONFIG |
555 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
557 cmd->hdr.command = cpu_to_le16(command);
558 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
561 cmd->type = cpu_to_le16(type);
562 cmd->action = cpu_to_le16(action);
564 ret = lbs_cmd_with_response(priv, command, cmd);
566 lbs_deb_leave(LBS_DEB_CMD);
570 int lbs_mesh_config_send(struct lbs_private *priv,
571 struct cmd_ds_mesh_config *cmd,
572 uint16_t action, uint16_t type)
576 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
579 ret = __lbs_mesh_config_send(priv, cmd, action, type);
583 /* This function is the CMD_MESH_CONFIG legacy function. It only handles the
584 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
585 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
586 * lbs_mesh_config_send.
588 int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
590 struct cmd_ds_mesh_config cmd;
591 struct mrvl_meshie *ie;
592 DECLARE_SSID_BUF(ssid);
594 memset(&cmd, 0, sizeof(cmd));
595 cmd.channel = cpu_to_le16(chan);
596 ie = (struct mrvl_meshie *)cmd.data;
599 case CMD_ACT_MESH_CONFIG_START:
600 ie->id = WLAN_EID_GENERIC;
601 ie->val.oui[0] = 0x00;
602 ie->val.oui[1] = 0x50;
603 ie->val.oui[2] = 0x43;
604 ie->val.type = MARVELL_MESH_IE_TYPE;
605 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
606 ie->val.version = MARVELL_MESH_IE_VERSION;
607 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
608 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
609 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
610 ie->val.mesh_id_len = priv->mesh_ssid_len;
611 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
612 ie->len = sizeof(struct mrvl_meshie_val) -
613 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
614 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
616 case CMD_ACT_MESH_CONFIG_STOP:
621 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
622 action, priv->mesh_tlv, chan,
623 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
625 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
630 /***************************************************************************
631 * Persistent configuration support
634 static int mesh_get_default_parameters(struct device *dev,
635 struct mrvl_mesh_defaults *defs)
637 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
638 struct cmd_ds_mesh_config cmd;
641 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
642 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
643 CMD_TYPE_MESH_GET_DEFAULTS);
648 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
654 * @brief Get function for sysfs attribute bootflag
656 static ssize_t bootflag_get(struct device *dev,
657 struct device_attribute *attr, char *buf)
659 struct mrvl_mesh_defaults defs;
662 ret = mesh_get_default_parameters(dev, &defs);
667 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
671 * @brief Set function for sysfs attribute bootflag
673 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
674 const char *buf, size_t count)
676 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
677 struct cmd_ds_mesh_config cmd;
681 memset(&cmd, 0, sizeof(cmd));
682 ret = sscanf(buf, "%d", &datum);
683 if ((ret != 1) || (datum > 1))
686 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
687 cmd.length = cpu_to_le16(sizeof(uint32_t));
688 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
689 CMD_TYPE_MESH_SET_BOOTFLAG);
697 * @brief Get function for sysfs attribute boottime
699 static ssize_t boottime_get(struct device *dev,
700 struct device_attribute *attr, char *buf)
702 struct mrvl_mesh_defaults defs;
705 ret = mesh_get_default_parameters(dev, &defs);
710 return snprintf(buf, 12, "%d\n", defs.boottime);
714 * @brief Set function for sysfs attribute boottime
716 static ssize_t boottime_set(struct device *dev,
717 struct device_attribute *attr, const char *buf, size_t count)
719 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
720 struct cmd_ds_mesh_config cmd;
724 memset(&cmd, 0, sizeof(cmd));
725 ret = sscanf(buf, "%d", &datum);
726 if ((ret != 1) || (datum > 255))
729 /* A too small boot time will result in the device booting into
730 * standalone (no-host) mode before the host can take control of it,
731 * so the change will be hard to revert. This may be a desired
732 * feature (e.g to configure a very fast boot time for devices that
733 * will not be attached to a host), but dangerous. So I'm enforcing a
734 * lower limit of 20 seconds: remove and recompile the driver if this
735 * does not work for you.
737 datum = (datum < 20) ? 20 : datum;
739 cmd.length = cpu_to_le16(sizeof(uint8_t));
740 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
741 CMD_TYPE_MESH_SET_BOOTTIME);
749 * @brief Get function for sysfs attribute channel
751 static ssize_t channel_get(struct device *dev,
752 struct device_attribute *attr, char *buf)
754 struct mrvl_mesh_defaults defs;
757 ret = mesh_get_default_parameters(dev, &defs);
762 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
766 * @brief Set function for sysfs attribute channel
768 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
769 const char *buf, size_t count)
771 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
772 struct cmd_ds_mesh_config cmd;
776 memset(&cmd, 0, sizeof(cmd));
777 ret = sscanf(buf, "%d", &datum);
778 if (ret != 1 || datum < 1 || datum > 11)
781 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
782 cmd.length = cpu_to_le16(sizeof(uint16_t));
783 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
784 CMD_TYPE_MESH_SET_DEF_CHANNEL);
792 * @brief Get function for sysfs attribute mesh_id
794 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
797 struct mrvl_mesh_defaults defs;
801 ret = mesh_get_default_parameters(dev, &defs);
806 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
807 lbs_pr_err("inconsistent mesh ID length");
808 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
811 /* SSID not null terminated: reserve room for \0 + \n */
812 maxlen = defs.meshie.val.mesh_id_len + 2;
813 maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
815 defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
817 return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
821 * @brief Set function for sysfs attribute mesh_id
823 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
824 const char *buf, size_t count)
826 struct cmd_ds_mesh_config cmd;
827 struct mrvl_mesh_defaults defs;
828 struct mrvl_meshie *ie;
829 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
833 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
836 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
837 ie = (struct mrvl_meshie *) &cmd.data[0];
839 /* fetch all other Information Element parameters */
840 ret = mesh_get_default_parameters(dev, &defs);
842 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
844 /* transfer IE elements */
845 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
848 memcpy(ie->val.mesh_id, buf, len);
850 ie->val.mesh_id_len = len;
852 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
854 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
855 CMD_TYPE_MESH_SET_MESH_IE);
863 * @brief Get function for sysfs attribute protocol_id
865 static ssize_t protocol_id_get(struct device *dev,
866 struct device_attribute *attr, char *buf)
868 struct mrvl_mesh_defaults defs;
871 ret = mesh_get_default_parameters(dev, &defs);
876 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
880 * @brief Set function for sysfs attribute protocol_id
882 static ssize_t protocol_id_set(struct device *dev,
883 struct device_attribute *attr, const char *buf, size_t count)
885 struct cmd_ds_mesh_config cmd;
886 struct mrvl_mesh_defaults defs;
887 struct mrvl_meshie *ie;
888 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
892 memset(&cmd, 0, sizeof(cmd));
893 ret = sscanf(buf, "%d", &datum);
894 if ((ret != 1) || (datum > 255))
897 /* fetch all other Information Element parameters */
898 ret = mesh_get_default_parameters(dev, &defs);
900 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
902 /* transfer IE elements */
903 ie = (struct mrvl_meshie *) &cmd.data[0];
904 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
905 /* update protocol id */
906 ie->val.active_protocol_id = datum;
908 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
909 CMD_TYPE_MESH_SET_MESH_IE);
917 * @brief Get function for sysfs attribute metric_id
919 static ssize_t metric_id_get(struct device *dev,
920 struct device_attribute *attr, char *buf)
922 struct mrvl_mesh_defaults defs;
925 ret = mesh_get_default_parameters(dev, &defs);
930 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
934 * @brief Set function for sysfs attribute metric_id
936 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
937 const char *buf, size_t count)
939 struct cmd_ds_mesh_config cmd;
940 struct mrvl_mesh_defaults defs;
941 struct mrvl_meshie *ie;
942 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
946 memset(&cmd, 0, sizeof(cmd));
947 ret = sscanf(buf, "%d", &datum);
948 if ((ret != 1) || (datum > 255))
951 /* fetch all other Information Element parameters */
952 ret = mesh_get_default_parameters(dev, &defs);
954 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
956 /* transfer IE elements */
957 ie = (struct mrvl_meshie *) &cmd.data[0];
958 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
959 /* update metric id */
960 ie->val.active_metric_id = datum;
962 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
963 CMD_TYPE_MESH_SET_MESH_IE);
971 * @brief Get function for sysfs attribute capability
973 static ssize_t capability_get(struct device *dev,
974 struct device_attribute *attr, char *buf)
976 struct mrvl_mesh_defaults defs;
979 ret = mesh_get_default_parameters(dev, &defs);
984 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
988 * @brief Set function for sysfs attribute capability
990 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
991 const char *buf, size_t count)
993 struct cmd_ds_mesh_config cmd;
994 struct mrvl_mesh_defaults defs;
995 struct mrvl_meshie *ie;
996 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1000 memset(&cmd, 0, sizeof(cmd));
1001 ret = sscanf(buf, "%d", &datum);
1002 if ((ret != 1) || (datum > 255))
1005 /* fetch all other Information Element parameters */
1006 ret = mesh_get_default_parameters(dev, &defs);
1008 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1010 /* transfer IE elements */
1011 ie = (struct mrvl_meshie *) &cmd.data[0];
1012 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1014 ie->val.mesh_capability = datum;
1016 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1017 CMD_TYPE_MESH_SET_MESH_IE);
1025 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
1026 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
1027 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
1028 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
1029 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
1030 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
1031 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
1033 static struct attribute *boot_opts_attrs[] = {
1034 &dev_attr_bootflag.attr,
1035 &dev_attr_boottime.attr,
1036 &dev_attr_channel.attr,
1040 static struct attribute_group boot_opts_group = {
1041 .name = "boot_options",
1042 .attrs = boot_opts_attrs,
1045 static struct attribute *mesh_ie_attrs[] = {
1046 &dev_attr_mesh_id.attr,
1047 &dev_attr_protocol_id.attr,
1048 &dev_attr_metric_id.attr,
1049 &dev_attr_capability.attr,
1053 static struct attribute_group mesh_ie_group = {
1055 .attrs = mesh_ie_attrs,
1058 void lbs_persist_config_init(struct net_device *dev)
1061 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
1062 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
1065 void lbs_persist_config_remove(struct net_device *dev)
1067 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
1068 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
1073 /***************************************************************************
1077 static const char *mesh_stat_strings[] = {
1078 "drop_duplicate_bcast",
1080 "drop_no_fwd_route",
1082 "fwded_unicast_cnt",
1088 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1089 struct ethtool_stats *stats, uint64_t *data)
1091 struct lbs_private *priv = dev->ml_priv;
1092 struct cmd_ds_mesh_access mesh_access;
1095 lbs_deb_enter(LBS_DEB_ETHTOOL);
1097 /* Get Mesh Statistics */
1098 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1101 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1105 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1106 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1107 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1108 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1109 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1110 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1111 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1112 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1114 data[0] = priv->mstats.fwd_drop_rbt;
1115 data[1] = priv->mstats.fwd_drop_ttl;
1116 data[2] = priv->mstats.fwd_drop_noroute;
1117 data[3] = priv->mstats.fwd_drop_nobuf;
1118 data[4] = priv->mstats.fwd_unicast_cnt;
1119 data[5] = priv->mstats.fwd_bcast_cnt;
1120 data[6] = priv->mstats.drop_blind;
1121 data[7] = priv->mstats.tx_failed_cnt;
1123 lbs_deb_enter(LBS_DEB_ETHTOOL);
1126 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1128 struct lbs_private *priv = dev->ml_priv;
1130 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1131 return MESH_STATS_NUM;
1136 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1137 uint32_t stringset, uint8_t *s)
1141 lbs_deb_enter(LBS_DEB_ETHTOOL);
1143 switch (stringset) {
1145 for (i = 0; i < MESH_STATS_NUM; i++) {
1146 memcpy(s + i * ETH_GSTRING_LEN,
1147 mesh_stat_strings[i],
1152 lbs_deb_enter(LBS_DEB_ETHTOOL);