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>
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 priv->mesh_connect_status = LBS_DISCONNECTED;
201 /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
202 /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
203 /* 5.110.22 have mesh command with 0xa3 command id */
204 /* 10.0.0.p0 FW brings in mesh config command with different id */
205 /* Check FW version MSB and initialize mesh_fw_ver */
206 if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
207 /* Enable mesh, if supported, and work out which TLV it uses.
208 0x100 + 291 is an unofficial value used in 5.110.20.pXX
209 0x100 + 37 is the official value used in 5.110.21.pXX
210 but we check them in that order because 20.pXX doesn't
211 give an error -- it just silently fails. */
213 /* 5.110.20.pXX firmware will fail the command if the channel
214 doesn't match the existing channel. But only if the TLV
215 is correct. If the channel is wrong, _BOTH_ versions will
216 give an error to 0x100+291, and allow 0x100+37 to succeed.
217 It's just that 5.110.20.pXX will not have done anything
220 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
221 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
223 priv->mesh_tlv = TLV_TYPE_MESH_ID;
224 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
229 if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
230 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
231 /* 10.0.0.pXX new firmwares should succeed with TLV
232 * 0x100+37; Do not invoke command with old TLV.
234 priv->mesh_tlv = TLV_TYPE_MESH_ID;
235 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
241 if (priv->mesh_tlv) {
242 sprintf(priv->mesh_ssid, "mesh");
243 priv->mesh_ssid_len = 4;
247 if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
248 lbs_pr_err("cannot register lbs_mesh attribute\n");
253 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
258 int lbs_deinit_mesh(struct lbs_private *priv)
260 struct net_device *dev = priv->dev;
263 lbs_deb_enter(LBS_DEB_MESH);
265 if (priv->mesh_tlv) {
266 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
270 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
276 * @brief This function closes the mshX interface
278 * @param dev A pointer to net_device structure
281 static int lbs_mesh_stop(struct net_device *dev)
283 struct lbs_private *priv = dev->ml_priv;
285 lbs_deb_enter(LBS_DEB_MESH);
286 spin_lock_irq(&priv->driver_lock);
289 priv->mesh_connect_status = LBS_DISCONNECTED;
291 netif_stop_queue(dev);
292 netif_carrier_off(dev);
294 spin_unlock_irq(&priv->driver_lock);
296 schedule_work(&priv->mcast_work);
298 lbs_deb_leave(LBS_DEB_MESH);
303 * @brief This function opens the mshX interface
305 * @param dev A pointer to net_device structure
306 * @return 0 or -EBUSY if monitor mode active
308 static int lbs_mesh_dev_open(struct net_device *dev)
310 struct lbs_private *priv = dev->ml_priv;
313 lbs_deb_enter(LBS_DEB_NET);
315 spin_lock_irq(&priv->driver_lock);
317 if (priv->monitormode) {
323 priv->mesh_connect_status = LBS_CONNECTED;
324 netif_carrier_on(dev);
326 if (!priv->tx_pending_len)
327 netif_wake_queue(dev);
330 spin_unlock_irq(&priv->driver_lock);
331 lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
335 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
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,
346 * @brief This function adds mshX interface
348 * @param priv A pointer to the struct lbs_private structure
349 * @return 0 if successful, -X otherwise
351 int lbs_add_mesh(struct lbs_private *priv)
353 struct net_device *mesh_dev = NULL;
356 lbs_deb_enter(LBS_DEB_MESH);
358 /* Allocate a virtual mesh device */
359 mesh_dev = alloc_netdev(0, "msh%d", ether_setup);
361 lbs_deb_mesh("init mshX device failed\n");
365 mesh_dev->ml_priv = priv;
366 priv->mesh_dev = mesh_dev;
368 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29))
369 mesh_dev->netdev_ops = &mesh_netdev_ops;
371 mesh_dev->open = lbs_mesh_dev_open;
372 mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
373 mesh_dev->stop = lbs_mesh_stop;
374 mesh_dev->set_mac_address = lbs_set_mac_address;
375 mesh_dev->set_multicast_list = lbs_set_multicast_list;
377 mesh_dev->ethtool_ops = &lbs_ethtool_ops;
378 memcpy(mesh_dev->dev_addr, priv->dev->dev_addr, ETH_ALEN);
380 SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
383 mesh_dev->wireless_handlers = &mesh_handler_def;
385 mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
386 /* Register virtual mesh interface */
387 ret = register_netdev(mesh_dev);
389 lbs_pr_err("cannot register mshX virtual interface\n");
393 ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
397 lbs_persist_config_init(mesh_dev);
399 /* Everything successful */
404 unregister_netdev(mesh_dev);
407 free_netdev(mesh_dev);
410 lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
414 void lbs_remove_mesh(struct lbs_private *priv)
416 struct net_device *mesh_dev;
418 mesh_dev = priv->mesh_dev;
422 lbs_deb_enter(LBS_DEB_MESH);
423 netif_stop_queue(mesh_dev);
424 netif_carrier_off(mesh_dev);
425 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
426 lbs_persist_config_remove(mesh_dev);
427 unregister_netdev(mesh_dev);
428 priv->mesh_dev = NULL;
429 free_netdev(mesh_dev);
430 lbs_deb_leave(LBS_DEB_MESH);
435 /***************************************************************************
436 * Sending and receiving
438 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
439 struct net_device *dev, struct rxpd *rxpd)
441 if (priv->mesh_dev) {
442 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
443 if (rxpd->rx_control & RxPD_MESH_FRAME)
444 dev = priv->mesh_dev;
445 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
446 if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
447 dev = priv->mesh_dev;
454 void lbs_mesh_set_txpd(struct lbs_private *priv,
455 struct net_device *dev, struct txpd *txpd)
457 if (dev == priv->mesh_dev) {
458 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
459 txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
460 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
461 txpd->u.bss.bss_num = MESH_IFACE_ID;
466 /***************************************************************************
467 * Mesh command handling
470 int lbs_cmd_bt_access(struct cmd_ds_command *cmd,
471 u16 cmd_action, void *pdata_buf)
473 struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
474 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
476 cmd->command = cpu_to_le16(CMD_BT_ACCESS);
477 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) +
478 sizeof(struct cmd_header));
480 bt_access->action = cpu_to_le16(cmd_action);
482 switch (cmd_action) {
483 case CMD_ACT_BT_ACCESS_ADD:
484 memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
485 lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr",
486 bt_access->addr1, 6);
488 case CMD_ACT_BT_ACCESS_DEL:
489 memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
490 lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr",
491 bt_access->addr1, 6);
493 case CMD_ACT_BT_ACCESS_LIST:
494 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
496 case CMD_ACT_BT_ACCESS_RESET:
498 case CMD_ACT_BT_ACCESS_SET_INVERT:
499 bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
501 case CMD_ACT_BT_ACCESS_GET_INVERT:
506 lbs_deb_leave(LBS_DEB_CMD);
510 int lbs_cmd_fwt_access(struct cmd_ds_command *cmd,
511 u16 cmd_action, void *pdata_buf)
513 struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
514 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
516 cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
517 cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) +
518 sizeof(struct cmd_header));
522 memcpy(fwt_access, pdata_buf, sizeof(*fwt_access));
524 memset(fwt_access, 0, sizeof(*fwt_access));
526 fwt_access->action = cpu_to_le16(cmd_action);
528 lbs_deb_leave(LBS_DEB_CMD);
532 int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
533 struct cmd_ds_mesh_access *cmd)
537 lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
539 cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
540 cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
543 cmd->action = cpu_to_le16(cmd_action);
545 ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
547 lbs_deb_leave(LBS_DEB_CMD);
551 static int __lbs_mesh_config_send(struct lbs_private *priv,
552 struct cmd_ds_mesh_config *cmd,
553 uint16_t action, uint16_t type)
556 u16 command = CMD_MESH_CONFIG_OLD;
558 lbs_deb_enter(LBS_DEB_CMD);
561 * Command id is 0xac for v10 FW along with mesh interface
562 * id in bits 14-13-12.
564 if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
565 command = CMD_MESH_CONFIG |
566 (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
568 cmd->hdr.command = cpu_to_le16(command);
569 cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
572 cmd->type = cpu_to_le16(type);
573 cmd->action = cpu_to_le16(action);
575 ret = lbs_cmd_with_response(priv, command, cmd);
577 lbs_deb_leave(LBS_DEB_CMD);
581 int lbs_mesh_config_send(struct lbs_private *priv,
582 struct cmd_ds_mesh_config *cmd,
583 uint16_t action, uint16_t type)
587 if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
590 ret = __lbs_mesh_config_send(priv, cmd, action, type);
594 /* This function is the CMD_MESH_CONFIG legacy function. It only handles the
595 * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG
596 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
597 * lbs_mesh_config_send.
599 int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan)
601 struct cmd_ds_mesh_config cmd;
602 struct mrvl_meshie *ie;
603 DECLARE_SSID_BUF(ssid);
605 memset(&cmd, 0, sizeof(cmd));
606 cmd.channel = cpu_to_le16(chan);
607 ie = (struct mrvl_meshie *)cmd.data;
610 case CMD_ACT_MESH_CONFIG_START:
611 ie->id = WLAN_EID_GENERIC;
612 ie->val.oui[0] = 0x00;
613 ie->val.oui[1] = 0x50;
614 ie->val.oui[2] = 0x43;
615 ie->val.type = MARVELL_MESH_IE_TYPE;
616 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
617 ie->val.version = MARVELL_MESH_IE_VERSION;
618 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
619 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
620 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
621 ie->val.mesh_id_len = priv->mesh_ssid_len;
622 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
623 ie->len = sizeof(struct mrvl_meshie_val) -
624 IEEE80211_MAX_SSID_LEN + priv->mesh_ssid_len;
625 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
627 case CMD_ACT_MESH_CONFIG_STOP:
632 lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n",
633 action, priv->mesh_tlv, chan,
634 print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len));
636 return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
641 /***************************************************************************
642 * Persistent configuration support
645 static int mesh_get_default_parameters(struct device *dev,
646 struct mrvl_mesh_defaults *defs)
648 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
649 struct cmd_ds_mesh_config cmd;
652 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
653 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
654 CMD_TYPE_MESH_GET_DEFAULTS);
659 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
665 * @brief Get function for sysfs attribute bootflag
667 static ssize_t bootflag_get(struct device *dev,
668 struct device_attribute *attr, char *buf)
670 struct mrvl_mesh_defaults defs;
673 ret = mesh_get_default_parameters(dev, &defs);
678 return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
682 * @brief Set function for sysfs attribute bootflag
684 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
685 const char *buf, size_t count)
687 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
688 struct cmd_ds_mesh_config cmd;
692 memset(&cmd, 0, sizeof(cmd));
693 ret = sscanf(buf, "%d", &datum);
694 if ((ret != 1) || (datum > 1))
697 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
698 cmd.length = cpu_to_le16(sizeof(uint32_t));
699 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
700 CMD_TYPE_MESH_SET_BOOTFLAG);
708 * @brief Get function for sysfs attribute boottime
710 static ssize_t boottime_get(struct device *dev,
711 struct device_attribute *attr, char *buf)
713 struct mrvl_mesh_defaults defs;
716 ret = mesh_get_default_parameters(dev, &defs);
721 return snprintf(buf, 12, "%d\n", defs.boottime);
725 * @brief Set function for sysfs attribute boottime
727 static ssize_t boottime_set(struct device *dev,
728 struct device_attribute *attr, const char *buf, size_t count)
730 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
731 struct cmd_ds_mesh_config cmd;
735 memset(&cmd, 0, sizeof(cmd));
736 ret = sscanf(buf, "%d", &datum);
737 if ((ret != 1) || (datum > 255))
740 /* A too small boot time will result in the device booting into
741 * standalone (no-host) mode before the host can take control of it,
742 * so the change will be hard to revert. This may be a desired
743 * feature (e.g to configure a very fast boot time for devices that
744 * will not be attached to a host), but dangerous. So I'm enforcing a
745 * lower limit of 20 seconds: remove and recompile the driver if this
746 * does not work for you.
748 datum = (datum < 20) ? 20 : datum;
750 cmd.length = cpu_to_le16(sizeof(uint8_t));
751 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
752 CMD_TYPE_MESH_SET_BOOTTIME);
760 * @brief Get function for sysfs attribute channel
762 static ssize_t channel_get(struct device *dev,
763 struct device_attribute *attr, char *buf)
765 struct mrvl_mesh_defaults defs;
768 ret = mesh_get_default_parameters(dev, &defs);
773 return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
777 * @brief Set function for sysfs attribute channel
779 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
780 const char *buf, size_t count)
782 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
783 struct cmd_ds_mesh_config cmd;
787 memset(&cmd, 0, sizeof(cmd));
788 ret = sscanf(buf, "%d", &datum);
789 if (ret != 1 || datum < 1 || datum > 11)
792 *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
793 cmd.length = cpu_to_le16(sizeof(uint16_t));
794 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
795 CMD_TYPE_MESH_SET_DEF_CHANNEL);
803 * @brief Get function for sysfs attribute mesh_id
805 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
808 struct mrvl_mesh_defaults defs;
812 ret = mesh_get_default_parameters(dev, &defs);
817 if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
818 lbs_pr_err("inconsistent mesh ID length");
819 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
822 /* SSID not null terminated: reserve room for \0 + \n */
823 maxlen = defs.meshie.val.mesh_id_len + 2;
824 maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
826 defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
828 return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
832 * @brief Set function for sysfs attribute mesh_id
834 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
835 const char *buf, size_t count)
837 struct cmd_ds_mesh_config cmd;
838 struct mrvl_mesh_defaults defs;
839 struct mrvl_meshie *ie;
840 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
844 if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
847 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
848 ie = (struct mrvl_meshie *) &cmd.data[0];
850 /* fetch all other Information Element parameters */
851 ret = mesh_get_default_parameters(dev, &defs);
853 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
855 /* transfer IE elements */
856 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
859 memcpy(ie->val.mesh_id, buf, len);
861 ie->val.mesh_id_len = len;
863 ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
865 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
866 CMD_TYPE_MESH_SET_MESH_IE);
874 * @brief Get function for sysfs attribute protocol_id
876 static ssize_t protocol_id_get(struct device *dev,
877 struct device_attribute *attr, char *buf)
879 struct mrvl_mesh_defaults defs;
882 ret = mesh_get_default_parameters(dev, &defs);
887 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
891 * @brief Set function for sysfs attribute protocol_id
893 static ssize_t protocol_id_set(struct device *dev,
894 struct device_attribute *attr, const char *buf, size_t count)
896 struct cmd_ds_mesh_config cmd;
897 struct mrvl_mesh_defaults defs;
898 struct mrvl_meshie *ie;
899 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
903 memset(&cmd, 0, sizeof(cmd));
904 ret = sscanf(buf, "%d", &datum);
905 if ((ret != 1) || (datum > 255))
908 /* fetch all other Information Element parameters */
909 ret = mesh_get_default_parameters(dev, &defs);
911 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
913 /* transfer IE elements */
914 ie = (struct mrvl_meshie *) &cmd.data[0];
915 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
916 /* update protocol id */
917 ie->val.active_protocol_id = datum;
919 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
920 CMD_TYPE_MESH_SET_MESH_IE);
928 * @brief Get function for sysfs attribute metric_id
930 static ssize_t metric_id_get(struct device *dev,
931 struct device_attribute *attr, char *buf)
933 struct mrvl_mesh_defaults defs;
936 ret = mesh_get_default_parameters(dev, &defs);
941 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
945 * @brief Set function for sysfs attribute metric_id
947 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
948 const char *buf, size_t count)
950 struct cmd_ds_mesh_config cmd;
951 struct mrvl_mesh_defaults defs;
952 struct mrvl_meshie *ie;
953 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
957 memset(&cmd, 0, sizeof(cmd));
958 ret = sscanf(buf, "%d", &datum);
959 if ((ret != 1) || (datum > 255))
962 /* fetch all other Information Element parameters */
963 ret = mesh_get_default_parameters(dev, &defs);
965 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
967 /* transfer IE elements */
968 ie = (struct mrvl_meshie *) &cmd.data[0];
969 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
970 /* update metric id */
971 ie->val.active_metric_id = datum;
973 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
974 CMD_TYPE_MESH_SET_MESH_IE);
982 * @brief Get function for sysfs attribute capability
984 static ssize_t capability_get(struct device *dev,
985 struct device_attribute *attr, char *buf)
987 struct mrvl_mesh_defaults defs;
990 ret = mesh_get_default_parameters(dev, &defs);
995 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
999 * @brief Set function for sysfs attribute capability
1001 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
1002 const char *buf, size_t count)
1004 struct cmd_ds_mesh_config cmd;
1005 struct mrvl_mesh_defaults defs;
1006 struct mrvl_meshie *ie;
1007 struct lbs_private *priv = to_net_dev(dev)->ml_priv;
1011 memset(&cmd, 0, sizeof(cmd));
1012 ret = sscanf(buf, "%d", &datum);
1013 if ((ret != 1) || (datum > 255))
1016 /* fetch all other Information Element parameters */
1017 ret = mesh_get_default_parameters(dev, &defs);
1019 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
1021 /* transfer IE elements */
1022 ie = (struct mrvl_meshie *) &cmd.data[0];
1023 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
1025 ie->val.mesh_capability = datum;
1027 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
1028 CMD_TYPE_MESH_SET_MESH_IE);
1036 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
1037 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
1038 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
1039 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
1040 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
1041 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
1042 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
1044 static struct attribute *boot_opts_attrs[] = {
1045 &dev_attr_bootflag.attr,
1046 &dev_attr_boottime.attr,
1047 &dev_attr_channel.attr,
1051 static struct attribute_group boot_opts_group = {
1052 .name = "boot_options",
1053 .attrs = boot_opts_attrs,
1056 static struct attribute *mesh_ie_attrs[] = {
1057 &dev_attr_mesh_id.attr,
1058 &dev_attr_protocol_id.attr,
1059 &dev_attr_metric_id.attr,
1060 &dev_attr_capability.attr,
1064 static struct attribute_group mesh_ie_group = {
1066 .attrs = mesh_ie_attrs,
1069 void lbs_persist_config_init(struct net_device *dev)
1072 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
1073 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
1076 void lbs_persist_config_remove(struct net_device *dev)
1078 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
1079 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
1084 /***************************************************************************
1088 static const char *mesh_stat_strings[] = {
1089 "drop_duplicate_bcast",
1091 "drop_no_fwd_route",
1093 "fwded_unicast_cnt",
1099 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1100 struct ethtool_stats *stats, uint64_t *data)
1102 struct lbs_private *priv = dev->ml_priv;
1103 struct cmd_ds_mesh_access mesh_access;
1106 lbs_deb_enter(LBS_DEB_ETHTOOL);
1108 /* Get Mesh Statistics */
1109 ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1112 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1116 priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1117 priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1118 priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1119 priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1120 priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1121 priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1122 priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1123 priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1125 data[0] = priv->mstats.fwd_drop_rbt;
1126 data[1] = priv->mstats.fwd_drop_ttl;
1127 data[2] = priv->mstats.fwd_drop_noroute;
1128 data[3] = priv->mstats.fwd_drop_nobuf;
1129 data[4] = priv->mstats.fwd_unicast_cnt;
1130 data[5] = priv->mstats.fwd_bcast_cnt;
1131 data[6] = priv->mstats.drop_blind;
1132 data[7] = priv->mstats.tx_failed_cnt;
1134 lbs_deb_enter(LBS_DEB_ETHTOOL);
1137 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1139 struct lbs_private *priv = dev->ml_priv;
1141 if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1142 return MESH_STATS_NUM;
1147 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1148 uint32_t stringset, uint8_t *s)
1152 lbs_deb_enter(LBS_DEB_ETHTOOL);
1154 switch (stringset) {
1156 for (i = 0; i < MESH_STATS_NUM; i++) {
1157 memcpy(s + i * ETH_GSTRING_LEN,
1158 mesh_stat_strings[i],
1163 lbs_deb_enter(LBS_DEB_ETHTOOL);