/* * Check mesh FW version and appropriately send the mesh start * command */ int lbs_init_mesh(struct lbs_private *priv) { int ret = 0; lbs_deb_enter(LBS_DEB_MESH); /* 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); if (priv->mesh_tlv) { sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; ret = 1; } lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; }
int lbs_init_mesh(struct lbs_private *priv) { int ret = 0; lbs_deb_enter(LBS_DEB_MESH); /* */ /* */ /* */ /* */ /* */ if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) { /* */ /* */ 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)) { /* */ priv->mesh_tlv = TLV_TYPE_MESH_ID; if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) priv->mesh_tlv = 0; } /* */ lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1); if (priv->mesh_tlv) { sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; ret = 1; } lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; }
/** * lbs_mesh_dev_open - open the mshX interface * * @dev: A pointer to &net_device structure * returns: 0 or -EBUSY if monitor mode active */ static int lbs_mesh_dev_open(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; int ret = 0; lbs_deb_enter(LBS_DEB_NET); 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, priv->channel); out: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; }
/** * lbs_mesh_dev_open - open the mshX interface * * @dev: A pointer to &net_device structure * returns: 0 or -EBUSY if monitor mode active */ static int 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)); out: return ret; }
/** * lbs_mesh_stop - close the mshX interface * * @dev: A pointer to &net_device structure * returns: 0 */ static int lbs_mesh_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_MESH); lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); spin_lock_irq(&priv->driver_lock); netif_stop_queue(dev); netif_carrier_off(dev); spin_unlock_irq(&priv->driver_lock); schedule_work(&priv->mcast_work); lbs_deb_leave(LBS_DEB_MESH); return 0; }
/** * lbs_mesh_stop - close the mshX interface * * @dev: A pointer to &net_device structure * returns: 0 */ static int lbs_mesh_stop(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, lbs_mesh_get_channel(priv)); spin_lock_irq(&priv->driver_lock); netif_stop_queue(dev); netif_carrier_off(dev); spin_unlock_irq(&priv->driver_lock); lbs_update_mcast(priv); if (!lbs_iface_active(priv)) lbs_stop_iface(priv); return 0; }
/** * Set function for sysfs attribute mesh */ static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { struct lbs_private *priv = to_net_dev(dev)->ml_priv; int enable; int ret, action = CMD_ACT_MESH_CONFIG_STOP; sscanf(buf, "%x", &enable); enable = !!enable; if (enable == !!priv->mesh_dev) return count; if (enable) action = CMD_ACT_MESH_CONFIG_START; ret = lbs_mesh_config(priv, action, priv->channel); if (ret) return ret; if (enable) lbs_add_mesh(priv); else lbs_remove_mesh(priv); return count; }
int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel) { return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel); }