/* * Command id is 0xac for v10 FW along with mesh interface * id in bits 14-13-12.
*/ if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
command = CMD_MESH_CONFIG |
(MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG)) return -EOPNOTSUPP;
ret = __lbs_mesh_config_send(priv, cmd, action, type); return ret;
}
/* This function is the CMD_MESH_CONFIG legacy function. It only handles the * START and STOP actions. The extended actions supported by CMD_MESH_CONFIG * are all handled by preparing a struct cmd_ds_mesh_config and passing it to * lbs_mesh_config_send.
*/ staticint lbs_mesh_config(struct lbs_private *priv, uint16_t action,
uint16_t chan)
{ struct wireless_dev *mesh_wdev; struct cmd_ds_mesh_config cmd; struct mrvl_meshie *ie;
/*************************************************************************** * Mesh sysfs support
*/
/* * Attributes exported through sysfs
*/
/** * anycast_mask_show - Get function for sysfs attribute anycast_mask * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t anycast_mask_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_access mesh_access; int ret;
memset(&mesh_access, 0, sizeof(mesh_access));
ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access); if (ret) return ret;
ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
&mesh_access); if (ret) return ret;
return strlen(buf);
}
/** * lbs_mesh_show - Get function for sysfs attribute mesh * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t lbs_mesh_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; return sysfs_emit(buf, "0x%X\n", !!priv->mesh_dev);
}
/** * lbs_mesh_store - Set function for sysfs attribute mesh * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer
*/ static ssize_t lbs_mesh_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; int ret, enable;
ret = kstrtoint(buf, 16, &enable); if (ret) return ret;
enable = !!enable; if (enable == !!priv->mesh_dev) return count;
if (enable)
lbs_add_mesh(priv); else
lbs_remove_mesh(priv);
return count;
}
/* * lbs_mesh attribute to be exported per ethX interface * through sysfs (/sys/class/net/ethX/lbs_mesh)
*/ static DEVICE_ATTR_RW(lbs_mesh);
/* * anycast_mask attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/anycast_mask)
*/ static DEVICE_ATTR_RW(anycast_mask);
/* * prb_rsp_limit attribute to be exported per mshX interface * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
*/ static DEVICE_ATTR_RW(prb_rsp_limit);
/** * bootflag_show - Get function for sysfs attribute bootflag * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t bootflag_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct mrvl_mesh_defaults defs; int ret;
/** * bootflag_store - Set function for sysfs attribute bootflag * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer
*/ static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd;
uint32_t datum; int ret;
ret = kstrtouint(buf, 10, &datum); if (ret) return ret; if (datum > 1) return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
*((__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);
}
/** * boottime_show - Get function for sysfs attribute boottime * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t boottime_show(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 sysfs_emit(buf, "%d\n", defs.boottime);
}
/** * boottime_store - Set function for sysfs attribute boottime * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer
*/ static ssize_t boottime_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd;
uint32_t datum; int ret;
ret = kstrtouint(buf, 10, &datum); if (ret) return ret; if (datum > 255) return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
/* 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);
}
/** * channel_show - Get function for sysfs attribute channel * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t channel_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct mrvl_mesh_defaults defs; int ret;
/** * channel_store - Set function for sysfs attribute channel * @dev: the &struct device * @attr: device attributes * @buf: buffer that contains new attribute value * @count: size of buffer
*/ static ssize_t channel_store(struct device *dev, struct device_attribute *attr, constchar *buf, size_t count)
{ struct lbs_private *priv = to_net_dev(dev)->ml_priv; struct cmd_ds_mesh_config cmd;
uint32_t datum; int ret;
ret = kstrtouint(buf, 10, &datum); if (ret) return ret; if (datum < 1 || datum > 11) return -EINVAL;
memset(&cmd, 0, sizeof(cmd));
*((__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);
}
/** * mesh_id_show - Get function for sysfs attribute mesh_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t mesh_id_show(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;
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
dev_err(dev, "inconsistent mesh ID length\n");
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
/* 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) - IEEE80211_MAX_SSID_LEN + 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);
}
/** * protocol_id_show - Get function for sysfs attribute protocol_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t protocol_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct mrvl_mesh_defaults defs; int ret;
/* 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);
}
/** * metric_id_show - Get function for sysfs attribute metric_id * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t metric_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct mrvl_mesh_defaults defs; int ret;
/* 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);
}
/** * capability_show - Get function for sysfs attribute capability * @dev: the &struct device * @attr: device attributes * @buf: buffer where data will be returned
*/ static ssize_t capability_show(struct device *dev, struct device_attribute *attr, char *buf)
{ struct mrvl_mesh_defaults defs; int ret;
/*************************************************************************** * Initializing and starting, stopping mesh
*/
/* * Check mesh FW version and appropriately send the mesh start * command
*/ void lbs_init_mesh(struct lbs_private *priv)
{ /* Determine mesh_fw_ver from fwrelease and fwcapinfo */ /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */ /* 5.110.22 have mesh command with 0xa3 command id */ /* 10.0.0.p0 FW brings in mesh config command with different id */ /* Check FW version MSB and initialize mesh_fw_ver */ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) { /* Enable mesh, if supported, and work out which TLV it uses. 0x100 + 291 is an unofficial value used in 5.110.20.pXX 0x100 + 37 is the official value used in 5.110.21.pXX but we check them in that order because 20.pXX doesn't
give an error -- it just silently fails. */
/* 5.110.20.pXX firmware will fail the command if the channel doesn't match the existing channel. But only if the TLV is correct. If the channel is wrong, _BOTH_ versions will give an error to 0x100+291, and allow 0x100+37 to succeed. It's just that 5.110.20.pXX will not have done anything
useful */
priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->mesh_tlv = 0;
}
} else if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) { /* 10.0.0.pXX new firmwares should succeed with TLV * 0x100+37; Do not invoke command with old TLV.
*/
priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
priv->mesh_tlv = 0;
}
/* Stop meshing until interface is brought up */
lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
}
lbs_update_mcast(priv); if (!lbs_iface_active(priv))
lbs_stop_iface(priv);
return 0;
}
/** * lbs_mesh_dev_open - open the mshX interface * * @dev: A pointer to &net_device structure * returns: 0 or -EBUSY if monitor mode active
*/ staticint lbs_mesh_dev_open(struct net_device *dev)
{ struct lbs_private *priv = dev->ml_priv; int ret = 0;
if (!priv->iface_running) {
ret = lbs_start_iface(priv); if (ret) goto out;
}
spin_lock_irq(&priv->driver_lock);
if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
ret = -EBUSY;
spin_unlock_irq(&priv->driver_lock); goto out;
}
netif_carrier_on(dev);
if (!priv->tx_pending_len)
netif_wake_queue(dev);
spin_unlock_irq(&priv->driver_lock);
ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
lbs_mesh_get_channel(priv));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.