Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0003 
0004 #include <linux/delay.h>
0005 #include <linux/etherdevice.h>
0006 #include <linux/hardirq.h>
0007 #include <linux/netdevice.h>
0008 #include <linux/if_ether.h>
0009 #include <linux/if_arp.h>
0010 #include <linux/kthread.h>
0011 #include <linux/kfifo.h>
0012 #include <net/cfg80211.h>
0013 
0014 #include "mesh.h"
0015 #include "decl.h"
0016 #include "cmd.h"
0017 
0018 
0019 static int lbs_add_mesh(struct lbs_private *priv);
0020 
0021 /***************************************************************************
0022  * Mesh command handling
0023  */
0024 
0025 static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
0026             struct cmd_ds_mesh_access *cmd)
0027 {
0028     int ret;
0029 
0030     cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
0031     cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
0032     cmd->hdr.result = 0;
0033 
0034     cmd->action = cpu_to_le16(cmd_action);
0035 
0036     ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
0037 
0038     return ret;
0039 }
0040 
0041 static int __lbs_mesh_config_send(struct lbs_private *priv,
0042                   struct cmd_ds_mesh_config *cmd,
0043                   uint16_t action, uint16_t type)
0044 {
0045     int ret;
0046     u16 command = CMD_MESH_CONFIG_OLD;
0047 
0048     /*
0049      * Command id is 0xac for v10 FW along with mesh interface
0050      * id in bits 14-13-12.
0051      */
0052     if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
0053         command = CMD_MESH_CONFIG |
0054               (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
0055 
0056     cmd->hdr.command = cpu_to_le16(command);
0057     cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
0058     cmd->hdr.result = 0;
0059 
0060     cmd->type = cpu_to_le16(type);
0061     cmd->action = cpu_to_le16(action);
0062 
0063     ret = lbs_cmd_with_response(priv, command, cmd);
0064 
0065     return ret;
0066 }
0067 
0068 static int lbs_mesh_config_send(struct lbs_private *priv,
0069              struct cmd_ds_mesh_config *cmd,
0070              uint16_t action, uint16_t type)
0071 {
0072     int ret;
0073 
0074     if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
0075         return -EOPNOTSUPP;
0076 
0077     ret = __lbs_mesh_config_send(priv, cmd, action, type);
0078     return ret;
0079 }
0080 
0081 /* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
0082  * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
0083  * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
0084  * lbs_mesh_config_send.
0085  */
0086 static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
0087         uint16_t chan)
0088 {
0089     struct wireless_dev *mesh_wdev;
0090     struct cmd_ds_mesh_config cmd;
0091     struct mrvl_meshie *ie;
0092 
0093     memset(&cmd, 0, sizeof(cmd));
0094     cmd.channel = cpu_to_le16(chan);
0095     ie = (struct mrvl_meshie *)cmd.data;
0096 
0097     switch (action) {
0098     case CMD_ACT_MESH_CONFIG_START:
0099         ie->id = WLAN_EID_VENDOR_SPECIFIC;
0100         ie->val.oui[0] = 0x00;
0101         ie->val.oui[1] = 0x50;
0102         ie->val.oui[2] = 0x43;
0103         ie->val.type = MARVELL_MESH_IE_TYPE;
0104         ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
0105         ie->val.version = MARVELL_MESH_IE_VERSION;
0106         ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
0107         ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
0108         ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
0109 
0110         if (priv->mesh_dev) {
0111             mesh_wdev = priv->mesh_dev->ieee80211_ptr;
0112             ie->val.mesh_id_len = mesh_wdev->u.mesh.id_up_len;
0113             memcpy(ie->val.mesh_id, mesh_wdev->u.mesh.id,
0114                         mesh_wdev->u.mesh.id_up_len);
0115         }
0116 
0117         ie->len = sizeof(struct mrvl_meshie_val) -
0118             IEEE80211_MAX_SSID_LEN + ie->val.mesh_id_len;
0119 
0120         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
0121         break;
0122     case CMD_ACT_MESH_CONFIG_STOP:
0123         break;
0124     default:
0125         return -1;
0126     }
0127     lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
0128             action, priv->mesh_tlv, chan, ie->val.mesh_id_len,
0129             ie->val.mesh_id);
0130 
0131     return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
0132 }
0133 
0134 int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
0135 {
0136     priv->mesh_channel = channel;
0137     return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
0138 }
0139 
0140 static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
0141 {
0142     return priv->mesh_channel ?: 1;
0143 }
0144 
0145 /***************************************************************************
0146  * Mesh sysfs support
0147  */
0148 
0149 /*
0150  * Attributes exported through sysfs
0151  */
0152 
0153 /**
0154  * anycast_mask_show - Get function for sysfs attribute anycast_mask
0155  * @dev: the &struct device
0156  * @attr: device attributes
0157  * @buf: buffer where data will be returned
0158  */
0159 static ssize_t anycast_mask_show(struct device *dev,
0160                  struct device_attribute *attr, char *buf)
0161 {
0162     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0163     struct cmd_ds_mesh_access mesh_access;
0164     int ret;
0165 
0166     memset(&mesh_access, 0, sizeof(mesh_access));
0167 
0168     ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
0169     if (ret)
0170         return ret;
0171 
0172     return sysfs_emit(buf, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
0173 }
0174 
0175 /**
0176  * anycast_mask_store - Set function for sysfs attribute anycast_mask
0177  * @dev: the &struct device
0178  * @attr: device attributes
0179  * @buf: buffer that contains new attribute value
0180  * @count: size of buffer
0181  */
0182 static ssize_t anycast_mask_store(struct device *dev,
0183                   struct device_attribute *attr,
0184                   const char *buf, size_t count)
0185 {
0186     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0187     struct cmd_ds_mesh_access mesh_access;
0188     uint32_t datum;
0189     int ret;
0190 
0191     memset(&mesh_access, 0, sizeof(mesh_access));
0192     sscanf(buf, "%x", &datum);
0193     mesh_access.data[0] = cpu_to_le32(datum);
0194 
0195     ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
0196     if (ret)
0197         return ret;
0198 
0199     return strlen(buf);
0200 }
0201 
0202 /**
0203  * prb_rsp_limit_show - Get function for sysfs attribute prb_rsp_limit
0204  * @dev: the &struct device
0205  * @attr: device attributes
0206  * @buf: buffer where data will be returned
0207  */
0208 static ssize_t prb_rsp_limit_show(struct device *dev,
0209                   struct device_attribute *attr, char *buf)
0210 {
0211     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0212     struct cmd_ds_mesh_access mesh_access;
0213     int ret;
0214     u32 retry_limit;
0215 
0216     memset(&mesh_access, 0, sizeof(mesh_access));
0217     mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
0218 
0219     ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
0220             &mesh_access);
0221     if (ret)
0222         return ret;
0223 
0224     retry_limit = le32_to_cpu(mesh_access.data[1]);
0225     return sysfs_emit(buf, "%d\n", retry_limit);
0226 }
0227 
0228 /**
0229  * prb_rsp_limit_store - Set function for sysfs attribute prb_rsp_limit
0230  * @dev: the &struct device
0231  * @attr: device attributes
0232  * @buf: buffer that contains new attribute value
0233  * @count: size of buffer
0234  */
0235 static ssize_t prb_rsp_limit_store(struct device *dev,
0236                    struct device_attribute *attr,
0237                    const char *buf, size_t count)
0238 {
0239     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0240     struct cmd_ds_mesh_access mesh_access;
0241     int ret;
0242     unsigned long retry_limit;
0243 
0244     memset(&mesh_access, 0, sizeof(mesh_access));
0245     mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
0246 
0247     ret = kstrtoul(buf, 10, &retry_limit);
0248     if (ret)
0249         return ret;
0250     if (retry_limit > 15)
0251         return -ENOTSUPP;
0252 
0253     mesh_access.data[1] = cpu_to_le32(retry_limit);
0254 
0255     ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
0256             &mesh_access);
0257     if (ret)
0258         return ret;
0259 
0260     return strlen(buf);
0261 }
0262 
0263 /**
0264  * lbs_mesh_show - Get function for sysfs attribute mesh
0265  * @dev: the &struct device
0266  * @attr: device attributes
0267  * @buf: buffer where data will be returned
0268  */
0269 static ssize_t lbs_mesh_show(struct device *dev,
0270                  struct device_attribute *attr, char *buf)
0271 {
0272     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0273     return sysfs_emit(buf, "0x%X\n", !!priv->mesh_dev);
0274 }
0275 
0276 /**
0277  * lbs_mesh_store - Set function for sysfs attribute mesh
0278  * @dev: the &struct device
0279  * @attr: device attributes
0280  * @buf: buffer that contains new attribute value
0281  * @count: size of buffer
0282  */
0283 static ssize_t lbs_mesh_store(struct device *dev,
0284                   struct device_attribute *attr,
0285                   const char *buf, size_t count)
0286 {
0287     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0288     int enable;
0289 
0290     sscanf(buf, "%x", &enable);
0291     enable = !!enable;
0292     if (enable == !!priv->mesh_dev)
0293         return count;
0294 
0295     if (enable)
0296         lbs_add_mesh(priv);
0297     else
0298         lbs_remove_mesh(priv);
0299 
0300     return count;
0301 }
0302 
0303 /*
0304  * lbs_mesh attribute to be exported per ethX interface
0305  * through sysfs (/sys/class/net/ethX/lbs_mesh)
0306  */
0307 static DEVICE_ATTR_RW(lbs_mesh);
0308 
0309 /*
0310  * anycast_mask attribute to be exported per mshX interface
0311  * through sysfs (/sys/class/net/mshX/anycast_mask)
0312  */
0313 static DEVICE_ATTR_RW(anycast_mask);
0314 
0315 /*
0316  * prb_rsp_limit attribute to be exported per mshX interface
0317  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
0318  */
0319 static DEVICE_ATTR_RW(prb_rsp_limit);
0320 
0321 static struct attribute *lbs_mesh_sysfs_entries[] = {
0322     &dev_attr_anycast_mask.attr,
0323     &dev_attr_prb_rsp_limit.attr,
0324     NULL,
0325 };
0326 
0327 static const struct attribute_group lbs_mesh_attr_group = {
0328     .attrs = lbs_mesh_sysfs_entries,
0329 };
0330 
0331 
0332 /***************************************************************************
0333  * Persistent configuration support
0334  */
0335 
0336 static int mesh_get_default_parameters(struct device *dev,
0337                        struct mrvl_mesh_defaults *defs)
0338 {
0339     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0340     struct cmd_ds_mesh_config cmd;
0341     int ret;
0342 
0343     memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
0344     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
0345                    CMD_TYPE_MESH_GET_DEFAULTS);
0346 
0347     if (ret)
0348         return -EOPNOTSUPP;
0349 
0350     memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
0351 
0352     return 0;
0353 }
0354 
0355 /**
0356  * bootflag_show - Get function for sysfs attribute bootflag
0357  * @dev: the &struct device
0358  * @attr: device attributes
0359  * @buf: buffer where data will be returned
0360  */
0361 static ssize_t bootflag_show(struct device *dev,
0362                  struct device_attribute *attr, char *buf)
0363 {
0364     struct mrvl_mesh_defaults defs;
0365     int ret;
0366 
0367     ret = mesh_get_default_parameters(dev, &defs);
0368 
0369     if (ret)
0370         return ret;
0371 
0372     return sysfs_emit(buf, "%d\n", le32_to_cpu(defs.bootflag));
0373 }
0374 
0375 /**
0376  * bootflag_store - Set function for sysfs attribute bootflag
0377  * @dev: the &struct device
0378  * @attr: device attributes
0379  * @buf: buffer that contains new attribute value
0380  * @count: size of buffer
0381  */
0382 static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
0383                   const char *buf, size_t count)
0384 {
0385     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0386     struct cmd_ds_mesh_config cmd;
0387     uint32_t datum;
0388     int ret;
0389 
0390     memset(&cmd, 0, sizeof(cmd));
0391     ret = sscanf(buf, "%d", &datum);
0392     if ((ret != 1) || (datum > 1))
0393         return -EINVAL;
0394 
0395     *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
0396     cmd.length = cpu_to_le16(sizeof(uint32_t));
0397     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0398                    CMD_TYPE_MESH_SET_BOOTFLAG);
0399     if (ret)
0400         return ret;
0401 
0402     return strlen(buf);
0403 }
0404 
0405 /**
0406  * boottime_show - Get function for sysfs attribute boottime
0407  * @dev: the &struct device
0408  * @attr: device attributes
0409  * @buf: buffer where data will be returned
0410  */
0411 static ssize_t boottime_show(struct device *dev,
0412                  struct device_attribute *attr, char *buf)
0413 {
0414     struct mrvl_mesh_defaults defs;
0415     int ret;
0416 
0417     ret = mesh_get_default_parameters(dev, &defs);
0418 
0419     if (ret)
0420         return ret;
0421 
0422     return sysfs_emit(buf, "%d\n", defs.boottime);
0423 }
0424 
0425 /**
0426  * boottime_store - Set function for sysfs attribute boottime
0427  * @dev: the &struct device
0428  * @attr: device attributes
0429  * @buf: buffer that contains new attribute value
0430  * @count: size of buffer
0431  */
0432 static ssize_t boottime_store(struct device *dev,
0433                   struct device_attribute *attr,
0434                   const char *buf, size_t count)
0435 {
0436     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0437     struct cmd_ds_mesh_config cmd;
0438     uint32_t datum;
0439     int ret;
0440 
0441     memset(&cmd, 0, sizeof(cmd));
0442     ret = sscanf(buf, "%d", &datum);
0443     if ((ret != 1) || (datum > 255))
0444         return -EINVAL;
0445 
0446     /* A too small boot time will result in the device booting into
0447      * standalone (no-host) mode before the host can take control of it,
0448      * so the change will be hard to revert.  This may be a desired
0449      * feature (e.g to configure a very fast boot time for devices that
0450      * will not be attached to a host), but dangerous.  So I'm enforcing a
0451      * lower limit of 20 seconds:  remove and recompile the driver if this
0452      * does not work for you.
0453      */
0454     datum = (datum < 20) ? 20 : datum;
0455     cmd.data[0] = datum;
0456     cmd.length = cpu_to_le16(sizeof(uint8_t));
0457     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0458                    CMD_TYPE_MESH_SET_BOOTTIME);
0459     if (ret)
0460         return ret;
0461 
0462     return strlen(buf);
0463 }
0464 
0465 /**
0466  * channel_show - Get function for sysfs attribute channel
0467  * @dev: the &struct device
0468  * @attr: device attributes
0469  * @buf: buffer where data will be returned
0470  */
0471 static ssize_t channel_show(struct device *dev,
0472                 struct device_attribute *attr, char *buf)
0473 {
0474     struct mrvl_mesh_defaults defs;
0475     int ret;
0476 
0477     ret = mesh_get_default_parameters(dev, &defs);
0478 
0479     if (ret)
0480         return ret;
0481 
0482     return sysfs_emit(buf, "%d\n", le16_to_cpu(defs.channel));
0483 }
0484 
0485 /**
0486  * channel_store - Set function for sysfs attribute channel
0487  * @dev: the &struct device
0488  * @attr: device attributes
0489  * @buf: buffer that contains new attribute value
0490  * @count: size of buffer
0491  */
0492 static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
0493                  const char *buf, size_t count)
0494 {
0495     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0496     struct cmd_ds_mesh_config cmd;
0497     uint32_t datum;
0498     int ret;
0499 
0500     memset(&cmd, 0, sizeof(cmd));
0501     ret = sscanf(buf, "%d", &datum);
0502     if (ret != 1 || datum < 1 || datum > 11)
0503         return -EINVAL;
0504 
0505     *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
0506     cmd.length = cpu_to_le16(sizeof(uint16_t));
0507     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0508                    CMD_TYPE_MESH_SET_DEF_CHANNEL);
0509     if (ret)
0510         return ret;
0511 
0512     return strlen(buf);
0513 }
0514 
0515 /**
0516  * mesh_id_show - Get function for sysfs attribute mesh_id
0517  * @dev: the &struct device
0518  * @attr: device attributes
0519  * @buf: buffer where data will be returned
0520  */
0521 static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr,
0522                 char *buf)
0523 {
0524     struct mrvl_mesh_defaults defs;
0525     int ret;
0526 
0527     ret = mesh_get_default_parameters(dev, &defs);
0528 
0529     if (ret)
0530         return ret;
0531 
0532     if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
0533         dev_err(dev, "inconsistent mesh ID length\n");
0534         defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
0535     }
0536 
0537     memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
0538     buf[defs.meshie.val.mesh_id_len] = '\n';
0539     buf[defs.meshie.val.mesh_id_len + 1] = '\0';
0540 
0541     return defs.meshie.val.mesh_id_len + 1;
0542 }
0543 
0544 /**
0545  * mesh_id_store - Set function for sysfs attribute mesh_id
0546  * @dev: the &struct device
0547  * @attr: device attributes
0548  * @buf: buffer that contains new attribute value
0549  * @count: size of buffer
0550  */
0551 static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr,
0552                  const char *buf, size_t count)
0553 {
0554     struct cmd_ds_mesh_config cmd;
0555     struct mrvl_mesh_defaults defs;
0556     struct mrvl_meshie *ie;
0557     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0558     int len;
0559     int ret;
0560 
0561     if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
0562         return -EINVAL;
0563 
0564     memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
0565     ie = (struct mrvl_meshie *) &cmd.data[0];
0566 
0567     /* fetch all other Information Element parameters */
0568     ret = mesh_get_default_parameters(dev, &defs);
0569 
0570     cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
0571 
0572     /* transfer IE elements */
0573     memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
0574 
0575     len = count - 1;
0576     memcpy(ie->val.mesh_id, buf, len);
0577     /* SSID len */
0578     ie->val.mesh_id_len = len;
0579     /* IE len */
0580     ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
0581 
0582     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0583                    CMD_TYPE_MESH_SET_MESH_IE);
0584     if (ret)
0585         return ret;
0586 
0587     return strlen(buf);
0588 }
0589 
0590 /**
0591  * protocol_id_show - Get function for sysfs attribute protocol_id
0592  * @dev: the &struct device
0593  * @attr: device attributes
0594  * @buf: buffer where data will be returned
0595  */
0596 static ssize_t protocol_id_show(struct device *dev,
0597                 struct device_attribute *attr,
0598                 char *buf)
0599 {
0600     struct mrvl_mesh_defaults defs;
0601     int ret;
0602 
0603     ret = mesh_get_default_parameters(dev, &defs);
0604 
0605     if (ret)
0606         return ret;
0607 
0608     return sysfs_emit(buf, "%d\n", defs.meshie.val.active_protocol_id);
0609 }
0610 
0611 /**
0612  * protocol_id_store - Set function for sysfs attribute protocol_id
0613  * @dev: the &struct device
0614  * @attr: device attributes
0615  * @buf: buffer that contains new attribute value
0616  * @count: size of buffer
0617  */
0618 static ssize_t protocol_id_store(struct device *dev,
0619                  struct device_attribute *attr,
0620                  const char *buf, size_t count)
0621 {
0622     struct cmd_ds_mesh_config cmd;
0623     struct mrvl_mesh_defaults defs;
0624     struct mrvl_meshie *ie;
0625     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0626     uint32_t datum;
0627     int ret;
0628 
0629     memset(&cmd, 0, sizeof(cmd));
0630     ret = sscanf(buf, "%d", &datum);
0631     if ((ret != 1) || (datum > 255))
0632         return -EINVAL;
0633 
0634     /* fetch all other Information Element parameters */
0635     ret = mesh_get_default_parameters(dev, &defs);
0636 
0637     cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
0638 
0639     /* transfer IE elements */
0640     ie = (struct mrvl_meshie *) &cmd.data[0];
0641     memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
0642     /* update protocol id */
0643     ie->val.active_protocol_id = datum;
0644 
0645     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0646                    CMD_TYPE_MESH_SET_MESH_IE);
0647     if (ret)
0648         return ret;
0649 
0650     return strlen(buf);
0651 }
0652 
0653 /**
0654  * metric_id_show - Get function for sysfs attribute metric_id
0655  * @dev: the &struct device
0656  * @attr: device attributes
0657  * @buf: buffer where data will be returned
0658  */
0659 static ssize_t metric_id_show(struct device *dev,
0660                   struct device_attribute *attr, char *buf)
0661 {
0662     struct mrvl_mesh_defaults defs;
0663     int ret;
0664 
0665     ret = mesh_get_default_parameters(dev, &defs);
0666 
0667     if (ret)
0668         return ret;
0669 
0670     return sysfs_emit(buf, "%d\n", defs.meshie.val.active_metric_id);
0671 }
0672 
0673 /**
0674  * metric_id_store - Set function for sysfs attribute metric_id
0675  * @dev: the &struct device
0676  * @attr: device attributes
0677  * @buf: buffer that contains new attribute value
0678  * @count: size of buffer
0679  */
0680 static ssize_t metric_id_store(struct device *dev,
0681                    struct device_attribute *attr,
0682                    const char *buf, size_t count)
0683 {
0684     struct cmd_ds_mesh_config cmd;
0685     struct mrvl_mesh_defaults defs;
0686     struct mrvl_meshie *ie;
0687     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0688     uint32_t datum;
0689     int ret;
0690 
0691     memset(&cmd, 0, sizeof(cmd));
0692     ret = sscanf(buf, "%d", &datum);
0693     if ((ret != 1) || (datum > 255))
0694         return -EINVAL;
0695 
0696     /* fetch all other Information Element parameters */
0697     ret = mesh_get_default_parameters(dev, &defs);
0698 
0699     cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
0700 
0701     /* transfer IE elements */
0702     ie = (struct mrvl_meshie *) &cmd.data[0];
0703     memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
0704     /* update metric id */
0705     ie->val.active_metric_id = datum;
0706 
0707     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0708                    CMD_TYPE_MESH_SET_MESH_IE);
0709     if (ret)
0710         return ret;
0711 
0712     return strlen(buf);
0713 }
0714 
0715 /**
0716  * capability_show - Get function for sysfs attribute capability
0717  * @dev: the &struct device
0718  * @attr: device attributes
0719  * @buf: buffer where data will be returned
0720  */
0721 static ssize_t capability_show(struct device *dev,
0722                    struct device_attribute *attr, char *buf)
0723 {
0724     struct mrvl_mesh_defaults defs;
0725     int ret;
0726 
0727     ret = mesh_get_default_parameters(dev, &defs);
0728 
0729     if (ret)
0730         return ret;
0731 
0732     return sysfs_emit(buf, "%d\n", defs.meshie.val.mesh_capability);
0733 }
0734 
0735 /**
0736  * capability_store - Set function for sysfs attribute capability
0737  * @dev: the &struct device
0738  * @attr: device attributes
0739  * @buf: buffer that contains new attribute value
0740  * @count: size of buffer
0741  */
0742 static ssize_t capability_store(struct device *dev,
0743                 struct device_attribute *attr,
0744                 const char *buf, size_t count)
0745 {
0746     struct cmd_ds_mesh_config cmd;
0747     struct mrvl_mesh_defaults defs;
0748     struct mrvl_meshie *ie;
0749     struct lbs_private *priv = to_net_dev(dev)->ml_priv;
0750     uint32_t datum;
0751     int ret;
0752 
0753     memset(&cmd, 0, sizeof(cmd));
0754     ret = sscanf(buf, "%d", &datum);
0755     if ((ret != 1) || (datum > 255))
0756         return -EINVAL;
0757 
0758     /* fetch all other Information Element parameters */
0759     ret = mesh_get_default_parameters(dev, &defs);
0760 
0761     cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
0762 
0763     /* transfer IE elements */
0764     ie = (struct mrvl_meshie *) &cmd.data[0];
0765     memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
0766     /* update value */
0767     ie->val.mesh_capability = datum;
0768 
0769     ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
0770                    CMD_TYPE_MESH_SET_MESH_IE);
0771     if (ret)
0772         return ret;
0773 
0774     return strlen(buf);
0775 }
0776 
0777 
0778 static DEVICE_ATTR_RW(bootflag);
0779 static DEVICE_ATTR_RW(boottime);
0780 static DEVICE_ATTR_RW(channel);
0781 static DEVICE_ATTR_RW(mesh_id);
0782 static DEVICE_ATTR_RW(protocol_id);
0783 static DEVICE_ATTR_RW(metric_id);
0784 static DEVICE_ATTR_RW(capability);
0785 
0786 static struct attribute *boot_opts_attrs[] = {
0787     &dev_attr_bootflag.attr,
0788     &dev_attr_boottime.attr,
0789     &dev_attr_channel.attr,
0790     NULL
0791 };
0792 
0793 static const struct attribute_group boot_opts_group = {
0794     .name = "boot_options",
0795     .attrs = boot_opts_attrs,
0796 };
0797 
0798 static struct attribute *mesh_ie_attrs[] = {
0799     &dev_attr_mesh_id.attr,
0800     &dev_attr_protocol_id.attr,
0801     &dev_attr_metric_id.attr,
0802     &dev_attr_capability.attr,
0803     NULL
0804 };
0805 
0806 static const struct attribute_group mesh_ie_group = {
0807     .name = "mesh_ie",
0808     .attrs = mesh_ie_attrs,
0809 };
0810 
0811 
0812 /***************************************************************************
0813  * Initializing and starting, stopping mesh
0814  */
0815 
0816 /*
0817  * Check mesh FW version and appropriately send the mesh start
0818  * command
0819  */
0820 void lbs_init_mesh(struct lbs_private *priv)
0821 {
0822     /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
0823     /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
0824     /* 5.110.22 have mesh command with 0xa3 command id */
0825     /* 10.0.0.p0 FW brings in mesh config command with different id */
0826     /* Check FW version MSB and initialize mesh_fw_ver */
0827     if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
0828         /* Enable mesh, if supported, and work out which TLV it uses.
0829            0x100 + 291 is an unofficial value used in 5.110.20.pXX
0830            0x100 + 37 is the official value used in 5.110.21.pXX
0831            but we check them in that order because 20.pXX doesn't
0832            give an error -- it just silently fails. */
0833 
0834         /* 5.110.20.pXX firmware will fail the command if the channel
0835            doesn't match the existing channel. But only if the TLV
0836            is correct. If the channel is wrong, _BOTH_ versions will
0837            give an error to 0x100+291, and allow 0x100+37 to succeed.
0838            It's just that 5.110.20.pXX will not have done anything
0839            useful */
0840 
0841         priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
0842         if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
0843             priv->mesh_tlv = TLV_TYPE_MESH_ID;
0844             if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
0845                 priv->mesh_tlv = 0;
0846         }
0847     } else
0848     if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
0849         (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
0850         /* 10.0.0.pXX new firmwares should succeed with TLV
0851          * 0x100+37; Do not invoke command with old TLV.
0852          */
0853         priv->mesh_tlv = TLV_TYPE_MESH_ID;
0854         if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
0855             priv->mesh_tlv = 0;
0856     }
0857 
0858     /* Stop meshing until interface is brought up */
0859     lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
0860 }
0861 
0862 void lbs_start_mesh(struct lbs_private *priv)
0863 {
0864     lbs_add_mesh(priv);
0865 
0866     if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
0867         netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
0868 }
0869 
0870 int lbs_deinit_mesh(struct lbs_private *priv)
0871 {
0872     struct net_device *dev = priv->dev;
0873     int ret = 0;
0874 
0875     if (priv->mesh_tlv) {
0876         device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
0877         ret = 1;
0878     }
0879 
0880     return ret;
0881 }
0882 
0883 
0884 /**
0885  * lbs_mesh_stop - close the mshX interface
0886  *
0887  * @dev:    A pointer to &net_device structure
0888  * returns: 0
0889  */
0890 static int lbs_mesh_stop(struct net_device *dev)
0891 {
0892     struct lbs_private *priv = dev->ml_priv;
0893 
0894     lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
0895         lbs_mesh_get_channel(priv));
0896 
0897     spin_lock_irq(&priv->driver_lock);
0898 
0899     netif_stop_queue(dev);
0900     netif_carrier_off(dev);
0901 
0902     spin_unlock_irq(&priv->driver_lock);
0903 
0904     lbs_update_mcast(priv);
0905     if (!lbs_iface_active(priv))
0906         lbs_stop_iface(priv);
0907 
0908     return 0;
0909 }
0910 
0911 /**
0912  * lbs_mesh_dev_open - open the mshX interface
0913  *
0914  * @dev:    A pointer to &net_device structure
0915  * returns: 0 or -EBUSY if monitor mode active
0916  */
0917 static int lbs_mesh_dev_open(struct net_device *dev)
0918 {
0919     struct lbs_private *priv = dev->ml_priv;
0920     int ret = 0;
0921 
0922     if (!priv->iface_running) {
0923         ret = lbs_start_iface(priv);
0924         if (ret)
0925             goto out;
0926     }
0927 
0928     spin_lock_irq(&priv->driver_lock);
0929 
0930     if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
0931         ret = -EBUSY;
0932         spin_unlock_irq(&priv->driver_lock);
0933         goto out;
0934     }
0935 
0936     netif_carrier_on(dev);
0937 
0938     if (!priv->tx_pending_len)
0939         netif_wake_queue(dev);
0940 
0941     spin_unlock_irq(&priv->driver_lock);
0942 
0943     ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
0944         lbs_mesh_get_channel(priv));
0945 
0946 out:
0947     return ret;
0948 }
0949 
0950 static const struct net_device_ops mesh_netdev_ops = {
0951     .ndo_open       = lbs_mesh_dev_open,
0952     .ndo_stop       = lbs_mesh_stop,
0953     .ndo_start_xmit     = lbs_hard_start_xmit,
0954     .ndo_set_mac_address    = lbs_set_mac_address,
0955     .ndo_set_rx_mode    = lbs_set_multicast_list,
0956 };
0957 
0958 /**
0959  * lbs_add_mesh - add mshX interface
0960  *
0961  * @priv:   A pointer to the &struct lbs_private structure
0962  * returns: 0 if successful, -X otherwise
0963  */
0964 static int lbs_add_mesh(struct lbs_private *priv)
0965 {
0966     struct net_device *mesh_dev = NULL;
0967     struct wireless_dev *mesh_wdev;
0968     int ret = 0;
0969 
0970     /* Allocate a virtual mesh device */
0971     mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
0972     if (!mesh_wdev) {
0973         lbs_deb_mesh("init mshX wireless device failed\n");
0974         ret = -ENOMEM;
0975         goto done;
0976     }
0977 
0978     mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
0979     if (!mesh_dev) {
0980         lbs_deb_mesh("init mshX device failed\n");
0981         ret = -ENOMEM;
0982         goto err_free_wdev;
0983     }
0984 
0985     mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
0986     mesh_wdev->wiphy = priv->wdev->wiphy;
0987 
0988     if (priv->mesh_tlv) {
0989         sprintf(mesh_wdev->u.mesh.id, "mesh");
0990         mesh_wdev->u.mesh.id_up_len = 4;
0991     }
0992 
0993     mesh_wdev->netdev = mesh_dev;
0994 
0995     mesh_dev->ml_priv = priv;
0996     mesh_dev->ieee80211_ptr = mesh_wdev;
0997     priv->mesh_dev = mesh_dev;
0998 
0999     mesh_dev->netdev_ops = &mesh_netdev_ops;
1000     mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1001     eth_hw_addr_inherit(mesh_dev, priv->dev);
1002 
1003     SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1004 
1005     mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1006     mesh_dev->sysfs_groups[0] = &lbs_mesh_attr_group;
1007     mesh_dev->sysfs_groups[1] = &boot_opts_group;
1008     mesh_dev->sysfs_groups[2] = &mesh_ie_group;
1009 
1010     /* Register virtual mesh interface */
1011     ret = register_netdev(mesh_dev);
1012     if (ret) {
1013         pr_err("cannot register mshX virtual interface\n");
1014         goto err_free_netdev;
1015     }
1016 
1017     /* Everything successful */
1018     ret = 0;
1019     goto done;
1020 
1021 err_free_netdev:
1022     free_netdev(mesh_dev);
1023 
1024 err_free_wdev:
1025     kfree(mesh_wdev);
1026 
1027 done:
1028     return ret;
1029 }
1030 
1031 void lbs_remove_mesh(struct lbs_private *priv)
1032 {
1033     struct net_device *mesh_dev;
1034 
1035     mesh_dev = priv->mesh_dev;
1036     if (!mesh_dev)
1037         return;
1038 
1039     netif_stop_queue(mesh_dev);
1040     netif_carrier_off(mesh_dev);
1041     unregister_netdev(mesh_dev);
1042     priv->mesh_dev = NULL;
1043     kfree(mesh_dev->ieee80211_ptr);
1044     free_netdev(mesh_dev);
1045 }
1046 
1047 
1048 /***************************************************************************
1049  * Sending and receiving
1050  */
1051 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1052     struct net_device *dev, struct rxpd *rxpd)
1053 {
1054     if (priv->mesh_dev) {
1055         if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1056             if (rxpd->rx_control & RxPD_MESH_FRAME)
1057                 dev = priv->mesh_dev;
1058         } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1059             if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1060                 dev = priv->mesh_dev;
1061         }
1062     }
1063     return dev;
1064 }
1065 
1066 
1067 void lbs_mesh_set_txpd(struct lbs_private *priv,
1068     struct net_device *dev, struct txpd *txpd)
1069 {
1070     if (dev == priv->mesh_dev) {
1071         if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1072             txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1073         else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1074             txpd->u.bss.bss_num = MESH_IFACE_ID;
1075     }
1076 }
1077 
1078 
1079 /***************************************************************************
1080  * Ethtool related
1081  */
1082 
1083 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1084     "drop_duplicate_bcast",
1085     "drop_ttl_zero",
1086     "drop_no_fwd_route",
1087     "drop_no_buffers",
1088     "fwded_unicast_cnt",
1089     "fwded_bcast_cnt",
1090     "drop_blind_table",
1091     "tx_failed_cnt"
1092 };
1093 
1094 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1095     struct ethtool_stats *stats, uint64_t *data)
1096 {
1097     struct lbs_private *priv = dev->ml_priv;
1098     struct cmd_ds_mesh_access mesh_access;
1099     int ret;
1100 
1101     /* Get Mesh Statistics */
1102     ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1103 
1104     if (ret) {
1105         memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1106         return;
1107     }
1108 
1109     priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1110     priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1111     priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1112     priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1113     priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1114     priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1115     priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1116     priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1117 
1118     data[0] = priv->mstats.fwd_drop_rbt;
1119     data[1] = priv->mstats.fwd_drop_ttl;
1120     data[2] = priv->mstats.fwd_drop_noroute;
1121     data[3] = priv->mstats.fwd_drop_nobuf;
1122     data[4] = priv->mstats.fwd_unicast_cnt;
1123     data[5] = priv->mstats.fwd_bcast_cnt;
1124     data[6] = priv->mstats.drop_blind;
1125     data[7] = priv->mstats.tx_failed_cnt;
1126 }
1127 
1128 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1129 {
1130     struct lbs_private *priv = dev->ml_priv;
1131 
1132     if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1133         return MESH_STATS_NUM;
1134 
1135     return -EOPNOTSUPP;
1136 }
1137 
1138 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1139     uint32_t stringset, uint8_t *s)
1140 {
1141     switch (stringset) {
1142     case ETH_SS_STATS:
1143         memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1144         break;
1145     }
1146 }