cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mesh.c (29336B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      3
      4#include <linux/delay.h>
      5#include <linux/etherdevice.h>
      6#include <linux/hardirq.h>
      7#include <linux/netdevice.h>
      8#include <linux/if_ether.h>
      9#include <linux/if_arp.h>
     10#include <linux/kthread.h>
     11#include <linux/kfifo.h>
     12#include <net/cfg80211.h>
     13
     14#include "mesh.h"
     15#include "decl.h"
     16#include "cmd.h"
     17
     18
     19static int lbs_add_mesh(struct lbs_private *priv);
     20
     21/***************************************************************************
     22 * Mesh command handling
     23 */
     24
     25static int lbs_mesh_access(struct lbs_private *priv, uint16_t cmd_action,
     26		    struct cmd_ds_mesh_access *cmd)
     27{
     28	int ret;
     29
     30	cmd->hdr.command = cpu_to_le16(CMD_MESH_ACCESS);
     31	cmd->hdr.size = cpu_to_le16(sizeof(*cmd));
     32	cmd->hdr.result = 0;
     33
     34	cmd->action = cpu_to_le16(cmd_action);
     35
     36	ret = lbs_cmd_with_response(priv, CMD_MESH_ACCESS, cmd);
     37
     38	return ret;
     39}
     40
     41static int __lbs_mesh_config_send(struct lbs_private *priv,
     42				  struct cmd_ds_mesh_config *cmd,
     43				  uint16_t action, uint16_t type)
     44{
     45	int ret;
     46	u16 command = CMD_MESH_CONFIG_OLD;
     47
     48	/*
     49	 * Command id is 0xac for v10 FW along with mesh interface
     50	 * id in bits 14-13-12.
     51	 */
     52	if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
     53		command = CMD_MESH_CONFIG |
     54			  (MESH_IFACE_ID << MESH_IFACE_BIT_OFFSET);
     55
     56	cmd->hdr.command = cpu_to_le16(command);
     57	cmd->hdr.size = cpu_to_le16(sizeof(struct cmd_ds_mesh_config));
     58	cmd->hdr.result = 0;
     59
     60	cmd->type = cpu_to_le16(type);
     61	cmd->action = cpu_to_le16(action);
     62
     63	ret = lbs_cmd_with_response(priv, command, cmd);
     64
     65	return ret;
     66}
     67
     68static int lbs_mesh_config_send(struct lbs_private *priv,
     69			 struct cmd_ds_mesh_config *cmd,
     70			 uint16_t action, uint16_t type)
     71{
     72	int ret;
     73
     74	if (!(priv->fwcapinfo & FW_CAPINFO_PERSISTENT_CONFIG))
     75		return -EOPNOTSUPP;
     76
     77	ret = __lbs_mesh_config_send(priv, cmd, action, type);
     78	return ret;
     79}
     80
     81/* This function is the CMD_MESH_CONFIG legacy function.  It only handles the
     82 * START and STOP actions.  The extended actions supported by CMD_MESH_CONFIG
     83 * are all handled by preparing a struct cmd_ds_mesh_config and passing it to
     84 * lbs_mesh_config_send.
     85 */
     86static int lbs_mesh_config(struct lbs_private *priv, uint16_t action,
     87		uint16_t chan)
     88{
     89	struct wireless_dev *mesh_wdev;
     90	struct cmd_ds_mesh_config cmd;
     91	struct mrvl_meshie *ie;
     92
     93	memset(&cmd, 0, sizeof(cmd));
     94	cmd.channel = cpu_to_le16(chan);
     95	ie = (struct mrvl_meshie *)cmd.data;
     96
     97	switch (action) {
     98	case CMD_ACT_MESH_CONFIG_START:
     99		ie->id = WLAN_EID_VENDOR_SPECIFIC;
    100		ie->val.oui[0] = 0x00;
    101		ie->val.oui[1] = 0x50;
    102		ie->val.oui[2] = 0x43;
    103		ie->val.type = MARVELL_MESH_IE_TYPE;
    104		ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
    105		ie->val.version = MARVELL_MESH_IE_VERSION;
    106		ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
    107		ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
    108		ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
    109
    110		if (priv->mesh_dev) {
    111			mesh_wdev = priv->mesh_dev->ieee80211_ptr;
    112			ie->val.mesh_id_len = mesh_wdev->mesh_id_up_len;
    113			memcpy(ie->val.mesh_id, mesh_wdev->ssid,
    114						mesh_wdev->mesh_id_up_len);
    115		}
    116
    117		ie->len = sizeof(struct mrvl_meshie_val) -
    118			IEEE80211_MAX_SSID_LEN + ie->val.mesh_id_len;
    119
    120		cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
    121		break;
    122	case CMD_ACT_MESH_CONFIG_STOP:
    123		break;
    124	default:
    125		return -1;
    126	}
    127	lbs_deb_cmd("mesh config action %d type %x channel %d SSID %*pE\n",
    128		    action, priv->mesh_tlv, chan, ie->val.mesh_id_len,
    129		    ie->val.mesh_id);
    130
    131	return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv);
    132}
    133
    134int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel)
    135{
    136	priv->mesh_channel = channel;
    137	return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel);
    138}
    139
    140static uint16_t lbs_mesh_get_channel(struct lbs_private *priv)
    141{
    142	return priv->mesh_channel ?: 1;
    143}
    144
    145/***************************************************************************
    146 * Mesh sysfs support
    147 */
    148
    149/*
    150 * Attributes exported through sysfs
    151 */
    152
    153/**
    154 * anycast_mask_show - Get function for sysfs attribute anycast_mask
    155 * @dev: the &struct device
    156 * @attr: device attributes
    157 * @buf: buffer where data will be returned
    158 */
    159static ssize_t anycast_mask_show(struct device *dev,
    160				 struct device_attribute *attr, char *buf)
    161{
    162	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    163	struct cmd_ds_mesh_access mesh_access;
    164	int ret;
    165
    166	memset(&mesh_access, 0, sizeof(mesh_access));
    167
    168	ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_ANYCAST, &mesh_access);
    169	if (ret)
    170		return ret;
    171
    172	return sysfs_emit(buf, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
    173}
    174
    175/**
    176 * anycast_mask_store - Set function for sysfs attribute anycast_mask
    177 * @dev: the &struct device
    178 * @attr: device attributes
    179 * @buf: buffer that contains new attribute value
    180 * @count: size of buffer
    181 */
    182static ssize_t anycast_mask_store(struct device *dev,
    183				  struct device_attribute *attr,
    184				  const char *buf, size_t count)
    185{
    186	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    187	struct cmd_ds_mesh_access mesh_access;
    188	uint32_t datum;
    189	int ret;
    190
    191	memset(&mesh_access, 0, sizeof(mesh_access));
    192	sscanf(buf, "%x", &datum);
    193	mesh_access.data[0] = cpu_to_le32(datum);
    194
    195	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
    196	if (ret)
    197		return ret;
    198
    199	return strlen(buf);
    200}
    201
    202/**
    203 * prb_rsp_limit_show - Get function for sysfs attribute prb_rsp_limit
    204 * @dev: the &struct device
    205 * @attr: device attributes
    206 * @buf: buffer where data will be returned
    207 */
    208static ssize_t prb_rsp_limit_show(struct device *dev,
    209				  struct device_attribute *attr, char *buf)
    210{
    211	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    212	struct cmd_ds_mesh_access mesh_access;
    213	int ret;
    214	u32 retry_limit;
    215
    216	memset(&mesh_access, 0, sizeof(mesh_access));
    217	mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
    218
    219	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
    220			&mesh_access);
    221	if (ret)
    222		return ret;
    223
    224	retry_limit = le32_to_cpu(mesh_access.data[1]);
    225	return sysfs_emit(buf, "%d\n", retry_limit);
    226}
    227
    228/**
    229 * prb_rsp_limit_store - Set function for sysfs attribute prb_rsp_limit
    230 * @dev: the &struct device
    231 * @attr: device attributes
    232 * @buf: buffer that contains new attribute value
    233 * @count: size of buffer
    234 */
    235static ssize_t prb_rsp_limit_store(struct device *dev,
    236				   struct device_attribute *attr,
    237				   const char *buf, size_t count)
    238{
    239	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    240	struct cmd_ds_mesh_access mesh_access;
    241	int ret;
    242	unsigned long retry_limit;
    243
    244	memset(&mesh_access, 0, sizeof(mesh_access));
    245	mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
    246
    247	ret = kstrtoul(buf, 10, &retry_limit);
    248	if (ret)
    249		return ret;
    250	if (retry_limit > 15)
    251		return -ENOTSUPP;
    252
    253	mesh_access.data[1] = cpu_to_le32(retry_limit);
    254
    255	ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
    256			&mesh_access);
    257	if (ret)
    258		return ret;
    259
    260	return strlen(buf);
    261}
    262
    263/**
    264 * lbs_mesh_show - Get function for sysfs attribute mesh
    265 * @dev: the &struct device
    266 * @attr: device attributes
    267 * @buf: buffer where data will be returned
    268 */
    269static ssize_t lbs_mesh_show(struct device *dev,
    270			     struct device_attribute *attr, char *buf)
    271{
    272	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    273	return sysfs_emit(buf, "0x%X\n", !!priv->mesh_dev);
    274}
    275
    276/**
    277 * lbs_mesh_store - Set function for sysfs attribute mesh
    278 * @dev: the &struct device
    279 * @attr: device attributes
    280 * @buf: buffer that contains new attribute value
    281 * @count: size of buffer
    282 */
    283static ssize_t lbs_mesh_store(struct device *dev,
    284			      struct device_attribute *attr,
    285			      const char *buf, size_t count)
    286{
    287	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    288	int enable;
    289
    290	sscanf(buf, "%x", &enable);
    291	enable = !!enable;
    292	if (enable == !!priv->mesh_dev)
    293		return count;
    294
    295	if (enable)
    296		lbs_add_mesh(priv);
    297	else
    298		lbs_remove_mesh(priv);
    299
    300	return count;
    301}
    302
    303/*
    304 * lbs_mesh attribute to be exported per ethX interface
    305 * through sysfs (/sys/class/net/ethX/lbs_mesh)
    306 */
    307static DEVICE_ATTR_RW(lbs_mesh);
    308
    309/*
    310 * anycast_mask attribute to be exported per mshX interface
    311 * through sysfs (/sys/class/net/mshX/anycast_mask)
    312 */
    313static DEVICE_ATTR_RW(anycast_mask);
    314
    315/*
    316 * prb_rsp_limit attribute to be exported per mshX interface
    317 * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
    318 */
    319static DEVICE_ATTR_RW(prb_rsp_limit);
    320
    321static struct attribute *lbs_mesh_sysfs_entries[] = {
    322	&dev_attr_anycast_mask.attr,
    323	&dev_attr_prb_rsp_limit.attr,
    324	NULL,
    325};
    326
    327static const struct attribute_group lbs_mesh_attr_group = {
    328	.attrs = lbs_mesh_sysfs_entries,
    329};
    330
    331
    332/***************************************************************************
    333 * Persistent configuration support
    334 */
    335
    336static int mesh_get_default_parameters(struct device *dev,
    337				       struct mrvl_mesh_defaults *defs)
    338{
    339	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    340	struct cmd_ds_mesh_config cmd;
    341	int ret;
    342
    343	memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
    344	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
    345				   CMD_TYPE_MESH_GET_DEFAULTS);
    346
    347	if (ret)
    348		return -EOPNOTSUPP;
    349
    350	memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
    351
    352	return 0;
    353}
    354
    355/**
    356 * bootflag_show - Get function for sysfs attribute bootflag
    357 * @dev: the &struct device
    358 * @attr: device attributes
    359 * @buf: buffer where data will be returned
    360 */
    361static ssize_t bootflag_show(struct device *dev,
    362			     struct device_attribute *attr, char *buf)
    363{
    364	struct mrvl_mesh_defaults defs;
    365	int ret;
    366
    367	ret = mesh_get_default_parameters(dev, &defs);
    368
    369	if (ret)
    370		return ret;
    371
    372	return sysfs_emit(buf, "%d\n", le32_to_cpu(defs.bootflag));
    373}
    374
    375/**
    376 * bootflag_store - Set function for sysfs attribute bootflag
    377 * @dev: the &struct device
    378 * @attr: device attributes
    379 * @buf: buffer that contains new attribute value
    380 * @count: size of buffer
    381 */
    382static ssize_t bootflag_store(struct device *dev, struct device_attribute *attr,
    383			      const char *buf, size_t count)
    384{
    385	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    386	struct cmd_ds_mesh_config cmd;
    387	uint32_t datum;
    388	int ret;
    389
    390	memset(&cmd, 0, sizeof(cmd));
    391	ret = sscanf(buf, "%d", &datum);
    392	if ((ret != 1) || (datum > 1))
    393		return -EINVAL;
    394
    395	*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
    396	cmd.length = cpu_to_le16(sizeof(uint32_t));
    397	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    398				   CMD_TYPE_MESH_SET_BOOTFLAG);
    399	if (ret)
    400		return ret;
    401
    402	return strlen(buf);
    403}
    404
    405/**
    406 * boottime_show - Get function for sysfs attribute boottime
    407 * @dev: the &struct device
    408 * @attr: device attributes
    409 * @buf: buffer where data will be returned
    410 */
    411static ssize_t boottime_show(struct device *dev,
    412			     struct device_attribute *attr, char *buf)
    413{
    414	struct mrvl_mesh_defaults defs;
    415	int ret;
    416
    417	ret = mesh_get_default_parameters(dev, &defs);
    418
    419	if (ret)
    420		return ret;
    421
    422	return sysfs_emit(buf, "%d\n", defs.boottime);
    423}
    424
    425/**
    426 * boottime_store - Set function for sysfs attribute boottime
    427 * @dev: the &struct device
    428 * @attr: device attributes
    429 * @buf: buffer that contains new attribute value
    430 * @count: size of buffer
    431 */
    432static ssize_t boottime_store(struct device *dev,
    433			      struct device_attribute *attr,
    434			      const char *buf, size_t count)
    435{
    436	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    437	struct cmd_ds_mesh_config cmd;
    438	uint32_t datum;
    439	int ret;
    440
    441	memset(&cmd, 0, sizeof(cmd));
    442	ret = sscanf(buf, "%d", &datum);
    443	if ((ret != 1) || (datum > 255))
    444		return -EINVAL;
    445
    446	/* A too small boot time will result in the device booting into
    447	 * standalone (no-host) mode before the host can take control of it,
    448	 * so the change will be hard to revert.  This may be a desired
    449	 * feature (e.g to configure a very fast boot time for devices that
    450	 * will not be attached to a host), but dangerous.  So I'm enforcing a
    451	 * lower limit of 20 seconds:  remove and recompile the driver if this
    452	 * does not work for you.
    453	 */
    454	datum = (datum < 20) ? 20 : datum;
    455	cmd.data[0] = datum;
    456	cmd.length = cpu_to_le16(sizeof(uint8_t));
    457	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    458				   CMD_TYPE_MESH_SET_BOOTTIME);
    459	if (ret)
    460		return ret;
    461
    462	return strlen(buf);
    463}
    464
    465/**
    466 * channel_show - Get function for sysfs attribute channel
    467 * @dev: the &struct device
    468 * @attr: device attributes
    469 * @buf: buffer where data will be returned
    470 */
    471static ssize_t channel_show(struct device *dev,
    472			    struct device_attribute *attr, char *buf)
    473{
    474	struct mrvl_mesh_defaults defs;
    475	int ret;
    476
    477	ret = mesh_get_default_parameters(dev, &defs);
    478
    479	if (ret)
    480		return ret;
    481
    482	return sysfs_emit(buf, "%d\n", le16_to_cpu(defs.channel));
    483}
    484
    485/**
    486 * channel_store - Set function for sysfs attribute channel
    487 * @dev: the &struct device
    488 * @attr: device attributes
    489 * @buf: buffer that contains new attribute value
    490 * @count: size of buffer
    491 */
    492static ssize_t channel_store(struct device *dev, struct device_attribute *attr,
    493			     const char *buf, size_t count)
    494{
    495	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    496	struct cmd_ds_mesh_config cmd;
    497	uint32_t datum;
    498	int ret;
    499
    500	memset(&cmd, 0, sizeof(cmd));
    501	ret = sscanf(buf, "%d", &datum);
    502	if (ret != 1 || datum < 1 || datum > 11)
    503		return -EINVAL;
    504
    505	*((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
    506	cmd.length = cpu_to_le16(sizeof(uint16_t));
    507	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    508				   CMD_TYPE_MESH_SET_DEF_CHANNEL);
    509	if (ret)
    510		return ret;
    511
    512	return strlen(buf);
    513}
    514
    515/**
    516 * mesh_id_show - Get function for sysfs attribute mesh_id
    517 * @dev: the &struct device
    518 * @attr: device attributes
    519 * @buf: buffer where data will be returned
    520 */
    521static ssize_t mesh_id_show(struct device *dev, struct device_attribute *attr,
    522			    char *buf)
    523{
    524	struct mrvl_mesh_defaults defs;
    525	int ret;
    526
    527	ret = mesh_get_default_parameters(dev, &defs);
    528
    529	if (ret)
    530		return ret;
    531
    532	if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
    533		dev_err(dev, "inconsistent mesh ID length\n");
    534		defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
    535	}
    536
    537	memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
    538	buf[defs.meshie.val.mesh_id_len] = '\n';
    539	buf[defs.meshie.val.mesh_id_len + 1] = '\0';
    540
    541	return defs.meshie.val.mesh_id_len + 1;
    542}
    543
    544/**
    545 * mesh_id_store - Set function for sysfs attribute mesh_id
    546 * @dev: the &struct device
    547 * @attr: device attributes
    548 * @buf: buffer that contains new attribute value
    549 * @count: size of buffer
    550 */
    551static ssize_t mesh_id_store(struct device *dev, struct device_attribute *attr,
    552			     const char *buf, size_t count)
    553{
    554	struct cmd_ds_mesh_config cmd;
    555	struct mrvl_mesh_defaults defs;
    556	struct mrvl_meshie *ie;
    557	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    558	int len;
    559	int ret;
    560
    561	if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
    562		return -EINVAL;
    563
    564	memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
    565	ie = (struct mrvl_meshie *) &cmd.data[0];
    566
    567	/* fetch all other Information Element parameters */
    568	ret = mesh_get_default_parameters(dev, &defs);
    569
    570	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
    571
    572	/* transfer IE elements */
    573	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
    574
    575	len = count - 1;
    576	memcpy(ie->val.mesh_id, buf, len);
    577	/* SSID len */
    578	ie->val.mesh_id_len = len;
    579	/* IE len */
    580	ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
    581
    582	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    583				   CMD_TYPE_MESH_SET_MESH_IE);
    584	if (ret)
    585		return ret;
    586
    587	return strlen(buf);
    588}
    589
    590/**
    591 * protocol_id_show - Get function for sysfs attribute protocol_id
    592 * @dev: the &struct device
    593 * @attr: device attributes
    594 * @buf: buffer where data will be returned
    595 */
    596static ssize_t protocol_id_show(struct device *dev,
    597				struct device_attribute *attr,
    598				char *buf)
    599{
    600	struct mrvl_mesh_defaults defs;
    601	int ret;
    602
    603	ret = mesh_get_default_parameters(dev, &defs);
    604
    605	if (ret)
    606		return ret;
    607
    608	return sysfs_emit(buf, "%d\n", defs.meshie.val.active_protocol_id);
    609}
    610
    611/**
    612 * protocol_id_store - Set function for sysfs attribute protocol_id
    613 * @dev: the &struct device
    614 * @attr: device attributes
    615 * @buf: buffer that contains new attribute value
    616 * @count: size of buffer
    617 */
    618static ssize_t protocol_id_store(struct device *dev,
    619				 struct device_attribute *attr,
    620				 const char *buf, size_t count)
    621{
    622	struct cmd_ds_mesh_config cmd;
    623	struct mrvl_mesh_defaults defs;
    624	struct mrvl_meshie *ie;
    625	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    626	uint32_t datum;
    627	int ret;
    628
    629	memset(&cmd, 0, sizeof(cmd));
    630	ret = sscanf(buf, "%d", &datum);
    631	if ((ret != 1) || (datum > 255))
    632		return -EINVAL;
    633
    634	/* fetch all other Information Element parameters */
    635	ret = mesh_get_default_parameters(dev, &defs);
    636
    637	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
    638
    639	/* transfer IE elements */
    640	ie = (struct mrvl_meshie *) &cmd.data[0];
    641	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
    642	/* update protocol id */
    643	ie->val.active_protocol_id = datum;
    644
    645	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    646				   CMD_TYPE_MESH_SET_MESH_IE);
    647	if (ret)
    648		return ret;
    649
    650	return strlen(buf);
    651}
    652
    653/**
    654 * metric_id_show - Get function for sysfs attribute metric_id
    655 * @dev: the &struct device
    656 * @attr: device attributes
    657 * @buf: buffer where data will be returned
    658 */
    659static ssize_t metric_id_show(struct device *dev,
    660			      struct device_attribute *attr, char *buf)
    661{
    662	struct mrvl_mesh_defaults defs;
    663	int ret;
    664
    665	ret = mesh_get_default_parameters(dev, &defs);
    666
    667	if (ret)
    668		return ret;
    669
    670	return sysfs_emit(buf, "%d\n", defs.meshie.val.active_metric_id);
    671}
    672
    673/**
    674 * metric_id_store - Set function for sysfs attribute metric_id
    675 * @dev: the &struct device
    676 * @attr: device attributes
    677 * @buf: buffer that contains new attribute value
    678 * @count: size of buffer
    679 */
    680static ssize_t metric_id_store(struct device *dev,
    681			       struct device_attribute *attr,
    682			       const char *buf, size_t count)
    683{
    684	struct cmd_ds_mesh_config cmd;
    685	struct mrvl_mesh_defaults defs;
    686	struct mrvl_meshie *ie;
    687	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    688	uint32_t datum;
    689	int ret;
    690
    691	memset(&cmd, 0, sizeof(cmd));
    692	ret = sscanf(buf, "%d", &datum);
    693	if ((ret != 1) || (datum > 255))
    694		return -EINVAL;
    695
    696	/* fetch all other Information Element parameters */
    697	ret = mesh_get_default_parameters(dev, &defs);
    698
    699	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
    700
    701	/* transfer IE elements */
    702	ie = (struct mrvl_meshie *) &cmd.data[0];
    703	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
    704	/* update metric id */
    705	ie->val.active_metric_id = datum;
    706
    707	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    708				   CMD_TYPE_MESH_SET_MESH_IE);
    709	if (ret)
    710		return ret;
    711
    712	return strlen(buf);
    713}
    714
    715/**
    716 * capability_show - Get function for sysfs attribute capability
    717 * @dev: the &struct device
    718 * @attr: device attributes
    719 * @buf: buffer where data will be returned
    720 */
    721static ssize_t capability_show(struct device *dev,
    722			       struct device_attribute *attr, char *buf)
    723{
    724	struct mrvl_mesh_defaults defs;
    725	int ret;
    726
    727	ret = mesh_get_default_parameters(dev, &defs);
    728
    729	if (ret)
    730		return ret;
    731
    732	return sysfs_emit(buf, "%d\n", defs.meshie.val.mesh_capability);
    733}
    734
    735/**
    736 * capability_store - Set function for sysfs attribute capability
    737 * @dev: the &struct device
    738 * @attr: device attributes
    739 * @buf: buffer that contains new attribute value
    740 * @count: size of buffer
    741 */
    742static ssize_t capability_store(struct device *dev,
    743				struct device_attribute *attr,
    744				const char *buf, size_t count)
    745{
    746	struct cmd_ds_mesh_config cmd;
    747	struct mrvl_mesh_defaults defs;
    748	struct mrvl_meshie *ie;
    749	struct lbs_private *priv = to_net_dev(dev)->ml_priv;
    750	uint32_t datum;
    751	int ret;
    752
    753	memset(&cmd, 0, sizeof(cmd));
    754	ret = sscanf(buf, "%d", &datum);
    755	if ((ret != 1) || (datum > 255))
    756		return -EINVAL;
    757
    758	/* fetch all other Information Element parameters */
    759	ret = mesh_get_default_parameters(dev, &defs);
    760
    761	cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
    762
    763	/* transfer IE elements */
    764	ie = (struct mrvl_meshie *) &cmd.data[0];
    765	memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
    766	/* update value */
    767	ie->val.mesh_capability = datum;
    768
    769	ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
    770				   CMD_TYPE_MESH_SET_MESH_IE);
    771	if (ret)
    772		return ret;
    773
    774	return strlen(buf);
    775}
    776
    777
    778static DEVICE_ATTR_RW(bootflag);
    779static DEVICE_ATTR_RW(boottime);
    780static DEVICE_ATTR_RW(channel);
    781static DEVICE_ATTR_RW(mesh_id);
    782static DEVICE_ATTR_RW(protocol_id);
    783static DEVICE_ATTR_RW(metric_id);
    784static DEVICE_ATTR_RW(capability);
    785
    786static struct attribute *boot_opts_attrs[] = {
    787	&dev_attr_bootflag.attr,
    788	&dev_attr_boottime.attr,
    789	&dev_attr_channel.attr,
    790	NULL
    791};
    792
    793static const struct attribute_group boot_opts_group = {
    794	.name = "boot_options",
    795	.attrs = boot_opts_attrs,
    796};
    797
    798static struct attribute *mesh_ie_attrs[] = {
    799	&dev_attr_mesh_id.attr,
    800	&dev_attr_protocol_id.attr,
    801	&dev_attr_metric_id.attr,
    802	&dev_attr_capability.attr,
    803	NULL
    804};
    805
    806static const struct attribute_group mesh_ie_group = {
    807	.name = "mesh_ie",
    808	.attrs = mesh_ie_attrs,
    809};
    810
    811
    812/***************************************************************************
    813 * Initializing and starting, stopping mesh
    814 */
    815
    816/*
    817 * Check mesh FW version and appropriately send the mesh start
    818 * command
    819 */
    820void lbs_init_mesh(struct lbs_private *priv)
    821{
    822	/* Determine mesh_fw_ver from fwrelease and fwcapinfo */
    823	/* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
    824	/* 5.110.22 have mesh command with 0xa3 command id */
    825	/* 10.0.0.p0 FW brings in mesh config command with different id */
    826	/* Check FW version MSB and initialize mesh_fw_ver */
    827	if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
    828		/* Enable mesh, if supported, and work out which TLV it uses.
    829		   0x100 + 291 is an unofficial value used in 5.110.20.pXX
    830		   0x100 + 37 is the official value used in 5.110.21.pXX
    831		   but we check them in that order because 20.pXX doesn't
    832		   give an error -- it just silently fails. */
    833
    834		/* 5.110.20.pXX firmware will fail the command if the channel
    835		   doesn't match the existing channel. But only if the TLV
    836		   is correct. If the channel is wrong, _BOTH_ versions will
    837		   give an error to 0x100+291, and allow 0x100+37 to succeed.
    838		   It's just that 5.110.20.pXX will not have done anything
    839		   useful */
    840
    841		priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
    842		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
    843			priv->mesh_tlv = TLV_TYPE_MESH_ID;
    844			if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
    845				priv->mesh_tlv = 0;
    846		}
    847	} else
    848	if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
    849		(priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
    850		/* 10.0.0.pXX new firmwares should succeed with TLV
    851		 * 0x100+37; Do not invoke command with old TLV.
    852		 */
    853		priv->mesh_tlv = TLV_TYPE_MESH_ID;
    854		if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
    855			priv->mesh_tlv = 0;
    856	}
    857
    858	/* Stop meshing until interface is brought up */
    859	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
    860}
    861
    862void lbs_start_mesh(struct lbs_private *priv)
    863{
    864	lbs_add_mesh(priv);
    865
    866	if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
    867		netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
    868}
    869
    870int lbs_deinit_mesh(struct lbs_private *priv)
    871{
    872	struct net_device *dev = priv->dev;
    873	int ret = 0;
    874
    875	if (priv->mesh_tlv) {
    876		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
    877		ret = 1;
    878	}
    879
    880	return ret;
    881}
    882
    883
    884/**
    885 * lbs_mesh_stop - close the mshX interface
    886 *
    887 * @dev:	A pointer to &net_device structure
    888 * returns:	0
    889 */
    890static int lbs_mesh_stop(struct net_device *dev)
    891{
    892	struct lbs_private *priv = dev->ml_priv;
    893
    894	lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
    895		lbs_mesh_get_channel(priv));
    896
    897	spin_lock_irq(&priv->driver_lock);
    898
    899	netif_stop_queue(dev);
    900	netif_carrier_off(dev);
    901
    902	spin_unlock_irq(&priv->driver_lock);
    903
    904	lbs_update_mcast(priv);
    905	if (!lbs_iface_active(priv))
    906		lbs_stop_iface(priv);
    907
    908	return 0;
    909}
    910
    911/**
    912 * lbs_mesh_dev_open - open the mshX interface
    913 *
    914 * @dev:	A pointer to &net_device structure
    915 * returns:	0 or -EBUSY if monitor mode active
    916 */
    917static int lbs_mesh_dev_open(struct net_device *dev)
    918{
    919	struct lbs_private *priv = dev->ml_priv;
    920	int ret = 0;
    921
    922	if (!priv->iface_running) {
    923		ret = lbs_start_iface(priv);
    924		if (ret)
    925			goto out;
    926	}
    927
    928	spin_lock_irq(&priv->driver_lock);
    929
    930	if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
    931		ret = -EBUSY;
    932		spin_unlock_irq(&priv->driver_lock);
    933		goto out;
    934	}
    935
    936	netif_carrier_on(dev);
    937
    938	if (!priv->tx_pending_len)
    939		netif_wake_queue(dev);
    940
    941	spin_unlock_irq(&priv->driver_lock);
    942
    943	ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
    944		lbs_mesh_get_channel(priv));
    945
    946out:
    947	return ret;
    948}
    949
    950static const struct net_device_ops mesh_netdev_ops = {
    951	.ndo_open		= lbs_mesh_dev_open,
    952	.ndo_stop 		= lbs_mesh_stop,
    953	.ndo_start_xmit		= lbs_hard_start_xmit,
    954	.ndo_set_mac_address	= lbs_set_mac_address,
    955	.ndo_set_rx_mode	= lbs_set_multicast_list,
    956};
    957
    958/**
    959 * lbs_add_mesh - add mshX interface
    960 *
    961 * @priv:	A pointer to the &struct lbs_private structure
    962 * returns:	0 if successful, -X otherwise
    963 */
    964static int lbs_add_mesh(struct lbs_private *priv)
    965{
    966	struct net_device *mesh_dev = NULL;
    967	struct wireless_dev *mesh_wdev;
    968	int ret = 0;
    969
    970	/* Allocate a virtual mesh device */
    971	mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
    972	if (!mesh_wdev) {
    973		lbs_deb_mesh("init mshX wireless device failed\n");
    974		ret = -ENOMEM;
    975		goto done;
    976	}
    977
    978	mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
    979	if (!mesh_dev) {
    980		lbs_deb_mesh("init mshX device failed\n");
    981		ret = -ENOMEM;
    982		goto err_free_wdev;
    983	}
    984
    985	mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
    986	mesh_wdev->wiphy = priv->wdev->wiphy;
    987
    988	if (priv->mesh_tlv) {
    989		sprintf(mesh_wdev->ssid, "mesh");
    990		mesh_wdev->mesh_id_up_len = 4;
    991	}
    992
    993	mesh_wdev->netdev = mesh_dev;
    994
    995	mesh_dev->ml_priv = priv;
    996	mesh_dev->ieee80211_ptr = mesh_wdev;
    997	priv->mesh_dev = mesh_dev;
    998
    999	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
   1021err_free_netdev:
   1022	free_netdev(mesh_dev);
   1023
   1024err_free_wdev:
   1025	kfree(mesh_wdev);
   1026
   1027done:
   1028	return ret;
   1029}
   1030
   1031void 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 */
   1051struct 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
   1067void 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
   1083static 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
   1094void 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
   1128int 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
   1138void 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}