#include #include #include #include #include #include #include #include "host.h" #include "decl.h" #include "dev.h" #include "wext.h" #include "debugfs.h" #include "scan.h" #include "assoc.h" #include "cmd.h" static int mesh_get_default_parameters(struct device *dev, struct mrvl_mesh_defaults *defs) { struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_config cmd; int ret; memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET, CMD_TYPE_MESH_GET_DEFAULTS); if (ret) return -EOPNOTSUPP; memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults)); return 0; } /** * @brief Get function for sysfs attribute bootflag */ static ssize_t bootflag_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag)); } /** * @brief Set function for sysfs attribute bootflag */ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if ((ret != 1) || (datum > 1)) return -EINVAL; *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum); cmd.length = cpu_to_le16(sizeof(uint32_t)); ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_BOOTFLAG); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute boottime */ static ssize_t boottime_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 12, "%d\n", defs.boottime); } /** * @brief Set function for sysfs attribute boottime */ static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if ((ret != 1) || (datum > 255)) return -EINVAL; /* A too small boot time will result in the device booting into * standalone (no-host) mode before the host can take control of it, * so the change will be hard to revert. This may be a desired * feature (e.g to configure a very fast boot time for devices that * will not be attached to a host), but dangerous. So I'm enforcing a * lower limit of 20 seconds: remove and recompile the driver if this * does not work for you. */ datum = (datum < 20) ? 20 : datum; cmd.data[0] = datum; cmd.length = cpu_to_le16(sizeof(uint8_t)); ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_BOOTTIME); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute channel */ static ssize_t channel_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel)); } /** * @brief Set function for sysfs attribute channel */ static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->priv; struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if (ret != 1 || datum < 1 || datum > 11) return -EINVAL; *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum); cmd.length = cpu_to_le16(sizeof(uint16_t)); ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_DEF_CHANNEL); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute mesh_id */ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int maxlen; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) { lbs_pr_err("inconsistent mesh ID length"); defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE; } /* SSID not null terminated: reserve room for \0 + \n */ maxlen = defs.meshie.val.mesh_id_len + 2; maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE; defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0'; return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id); } /** * @brief Set function for sysfs attribute mesh_id */ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; struct lbs_private *priv = to_net_dev(dev)->priv; int len; int ret; if (count < 2 || count > IW_ESSID_MAX_SIZE + 1) return -EINVAL; memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config)); ie = (struct mrvl_meshie *) &cmd.data[0]; /* fetch all other Information Element parameters */ ret = mesh_get_default_parameters(dev, &defs); cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); /* transfer IE elements */ memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); len = count - 1; memcpy(ie->val.mesh_id, buf, len); /* SSID len */ ie->val.mesh_id_len = len; /* IE len */ ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute protocol_id */ static ssize_t protocol_id_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id); } /** * @brief Set function for sysfs attribute protocol_id */ static ssize_t protocol_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; struct lbs_private *priv = to_net_dev(dev)->priv; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ ret = mesh_get_default_parameters(dev, &defs); cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); /* transfer IE elements */ ie = (struct mrvl_meshie *) &cmd.data[0]; memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); /* update protocol id */ ie->val.active_protocol_id = datum; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute metric_id */ static ssize_t metric_id_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id); } /** * @brief Set function for sysfs attribute metric_id */ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; struct lbs_private *priv = to_net_dev(dev)->priv; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ ret = mesh_get_default_parameters(dev, &defs); cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); /* transfer IE elements */ ie = (struct mrvl_meshie *) &cmd.data[0]; memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); /* update metric id */ ie->val.active_metric_id = datum; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); if (ret) return ret; return strlen(buf); } /** * @brief Get function for sysfs attribute capability */ static ssize_t capability_get(struct device *dev, struct device_attribute *attr, char *buf) { struct mrvl_mesh_defaults defs; int ret; ret = mesh_get_default_parameters(dev, &defs); if (ret) return ret; return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability); } /** * @brief Set function for sysfs attribute capability */ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; struct lbs_private *priv = to_net_dev(dev)->priv; uint32_t datum; int ret; memset(&cmd, 0, sizeof(cmd)); ret = sscanf(buf, "%d", &datum); if ((ret != 1) || (datum > 255)) return -EINVAL; /* fetch all other Information Element parameters */ ret = mesh_get_default_parameters(dev, &defs); cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie)); /* transfer IE elements */ ie = (struct mrvl_meshie *) &cmd.data[0]; memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie)); /* update value */ ie->val.mesh_capability = datum; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); if (ret) return ret; return strlen(buf); } static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set); static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set); static DEVICE_ATTR(channel, 0644, channel_get, channel_set); static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set); static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set); static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set); static DEVICE_ATTR(capability, 0644, capability_get, capability_set); static struct attribute *boot_opts_attrs[] = { &dev_attr_bootflag.attr, &dev_attr_boottime.attr, &dev_attr_channel.attr, NULL }; static struct attribute_group boot_opts_group = { .name = "boot_options", .attrs = boot_opts_attrs, }; static struct attribute *mesh_ie_attrs[] = { &dev_attr_mesh_id.attr, &dev_attr_protocol_id.attr, &dev_attr_metric_id.attr, &dev_attr_capability.attr, NULL }; static struct attribute_group mesh_ie_group = { .name = "mesh_ie", .attrs = mesh_ie_attrs, }; void lbs_persist_config_init(struct net_device *dev) { int ret; ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group); ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group); } void lbs_persist_config_remove(struct net_device *dev) { sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group); sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group); }