root/drivers/net/wireless/marvell/libertas/mesh.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lbs_mesh_access
  2. __lbs_mesh_config_send
  3. lbs_mesh_config_send
  4. lbs_mesh_config
  5. lbs_mesh_set_channel
  6. lbs_mesh_get_channel
  7. lbs_anycast_get
  8. lbs_anycast_set
  9. lbs_prb_rsp_limit_get
  10. lbs_prb_rsp_limit_set
  11. lbs_mesh_get
  12. lbs_mesh_set
  13. mesh_get_default_parameters
  14. bootflag_get
  15. bootflag_set
  16. boottime_get
  17. boottime_set
  18. channel_get
  19. channel_set
  20. mesh_id_get
  21. mesh_id_set
  22. protocol_id_get
  23. protocol_id_set
  24. metric_id_get
  25. metric_id_set
  26. capability_get
  27. capability_set
  28. lbs_persist_config_init
  29. lbs_persist_config_remove
  30. lbs_init_mesh
  31. lbs_start_mesh
  32. lbs_deinit_mesh
  33. lbs_mesh_stop
  34. lbs_mesh_dev_open
  35. lbs_add_mesh
  36. lbs_remove_mesh
  37. lbs_mesh_set_dev
  38. lbs_mesh_set_txpd
  39. lbs_mesh_ethtool_get_stats
  40. lbs_mesh_ethtool_get_sset_count
  41. lbs_mesh_ethtool_get_strings

   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 
  19 static int lbs_add_mesh(struct lbs_private *priv);
  20 
  21 /***************************************************************************
  22  * Mesh command handling
  23  */
  24 
  25 static 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 
  41 static 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 
  68 static 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  */
  86 static 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 
 134 int 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 
 140 static 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  * lbs_anycast_get - 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  */
 159 static ssize_t lbs_anycast_get(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 snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
 173 }
 174 
 175 /**
 176  * lbs_anycast_set - 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  */
 182 static ssize_t lbs_anycast_set(struct device *dev,
 183                 struct device_attribute *attr, const char * buf, size_t count)
 184 {
 185         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 186         struct cmd_ds_mesh_access mesh_access;
 187         uint32_t datum;
 188         int ret;
 189 
 190         memset(&mesh_access, 0, sizeof(mesh_access));
 191         sscanf(buf, "%x", &datum);
 192         mesh_access.data[0] = cpu_to_le32(datum);
 193 
 194         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_ANYCAST, &mesh_access);
 195         if (ret)
 196                 return ret;
 197 
 198         return strlen(buf);
 199 }
 200 
 201 /**
 202  * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
 203  * @dev: the &struct device
 204  * @attr: device attributes
 205  * @buf: buffer where data will be returned
 206  */
 207 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
 208                 struct device_attribute *attr, char *buf)
 209 {
 210         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 211         struct cmd_ds_mesh_access mesh_access;
 212         int ret;
 213         u32 retry_limit;
 214 
 215         memset(&mesh_access, 0, sizeof(mesh_access));
 216         mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET);
 217 
 218         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
 219                         &mesh_access);
 220         if (ret)
 221                 return ret;
 222 
 223         retry_limit = le32_to_cpu(mesh_access.data[1]);
 224         return snprintf(buf, 10, "%d\n", retry_limit);
 225 }
 226 
 227 /**
 228  * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
 229  * @dev: the &struct device
 230  * @attr: device attributes
 231  * @buf: buffer that contains new attribute value
 232  * @count: size of buffer
 233  */
 234 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
 235                 struct device_attribute *attr, const char *buf, size_t count)
 236 {
 237         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 238         struct cmd_ds_mesh_access mesh_access;
 239         int ret;
 240         unsigned long retry_limit;
 241 
 242         memset(&mesh_access, 0, sizeof(mesh_access));
 243         mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET);
 244 
 245         ret = kstrtoul(buf, 10, &retry_limit);
 246         if (ret)
 247                 return ret;
 248         if (retry_limit > 15)
 249                 return -ENOTSUPP;
 250 
 251         mesh_access.data[1] = cpu_to_le32(retry_limit);
 252 
 253         ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT,
 254                         &mesh_access);
 255         if (ret)
 256                 return ret;
 257 
 258         return strlen(buf);
 259 }
 260 
 261 /**
 262  * lbs_mesh_get - Get function for sysfs attribute mesh
 263  * @dev: the &struct device
 264  * @attr: device attributes
 265  * @buf: buffer where data will be returned
 266  */
 267 static ssize_t lbs_mesh_get(struct device *dev,
 268                 struct device_attribute *attr, char * buf)
 269 {
 270         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 271         return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 272 }
 273 
 274 /**
 275  * lbs_mesh_set - Set function for sysfs attribute mesh
 276  * @dev: the &struct device
 277  * @attr: device attributes
 278  * @buf: buffer that contains new attribute value
 279  * @count: size of buffer
 280  */
 281 static ssize_t lbs_mesh_set(struct device *dev,
 282                 struct device_attribute *attr, const char * buf, size_t count)
 283 {
 284         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 285         int enable;
 286 
 287         sscanf(buf, "%x", &enable);
 288         enable = !!enable;
 289         if (enable == !!priv->mesh_dev)
 290                 return count;
 291 
 292         if (enable)
 293                 lbs_add_mesh(priv);
 294         else
 295                 lbs_remove_mesh(priv);
 296 
 297         return count;
 298 }
 299 
 300 /*
 301  * lbs_mesh attribute to be exported per ethX interface
 302  * through sysfs (/sys/class/net/ethX/lbs_mesh)
 303  */
 304 static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
 305 
 306 /*
 307  * anycast_mask attribute to be exported per mshX interface
 308  * through sysfs (/sys/class/net/mshX/anycast_mask)
 309  */
 310 static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
 311 
 312 /*
 313  * prb_rsp_limit attribute to be exported per mshX interface
 314  * through sysfs (/sys/class/net/mshX/prb_rsp_limit)
 315  */
 316 static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get,
 317                 lbs_prb_rsp_limit_set);
 318 
 319 static struct attribute *lbs_mesh_sysfs_entries[] = {
 320         &dev_attr_anycast_mask.attr,
 321         &dev_attr_prb_rsp_limit.attr,
 322         NULL,
 323 };
 324 
 325 static const struct attribute_group lbs_mesh_attr_group = {
 326         .attrs = lbs_mesh_sysfs_entries,
 327 };
 328 
 329 
 330 /***************************************************************************
 331  * Persistent configuration support
 332  */
 333 
 334 static int mesh_get_default_parameters(struct device *dev,
 335                                        struct mrvl_mesh_defaults *defs)
 336 {
 337         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 338         struct cmd_ds_mesh_config cmd;
 339         int ret;
 340 
 341         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
 342         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
 343                                    CMD_TYPE_MESH_GET_DEFAULTS);
 344 
 345         if (ret)
 346                 return -EOPNOTSUPP;
 347 
 348         memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
 349 
 350         return 0;
 351 }
 352 
 353 /**
 354  * bootflag_get - Get function for sysfs attribute bootflag
 355  * @dev: the &struct device
 356  * @attr: device attributes
 357  * @buf: buffer where data will be returned
 358  */
 359 static ssize_t bootflag_get(struct device *dev,
 360                             struct device_attribute *attr, char *buf)
 361 {
 362         struct mrvl_mesh_defaults defs;
 363         int ret;
 364 
 365         ret = mesh_get_default_parameters(dev, &defs);
 366 
 367         if (ret)
 368                 return ret;
 369 
 370         return snprintf(buf, 12, "%d\n", le32_to_cpu(defs.bootflag));
 371 }
 372 
 373 /**
 374  * bootflag_set - Set function for sysfs attribute bootflag
 375  * @dev: the &struct device
 376  * @attr: device attributes
 377  * @buf: buffer that contains new attribute value
 378  * @count: size of buffer
 379  */
 380 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
 381                             const char *buf, size_t count)
 382 {
 383         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 384         struct cmd_ds_mesh_config cmd;
 385         uint32_t datum;
 386         int ret;
 387 
 388         memset(&cmd, 0, sizeof(cmd));
 389         ret = sscanf(buf, "%d", &datum);
 390         if ((ret != 1) || (datum > 1))
 391                 return -EINVAL;
 392 
 393         *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
 394         cmd.length = cpu_to_le16(sizeof(uint32_t));
 395         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 396                                    CMD_TYPE_MESH_SET_BOOTFLAG);
 397         if (ret)
 398                 return ret;
 399 
 400         return strlen(buf);
 401 }
 402 
 403 /**
 404  * boottime_get - Get function for sysfs attribute boottime
 405  * @dev: the &struct device
 406  * @attr: device attributes
 407  * @buf: buffer where data will be returned
 408  */
 409 static ssize_t boottime_get(struct device *dev,
 410                             struct device_attribute *attr, char *buf)
 411 {
 412         struct mrvl_mesh_defaults defs;
 413         int ret;
 414 
 415         ret = mesh_get_default_parameters(dev, &defs);
 416 
 417         if (ret)
 418                 return ret;
 419 
 420         return snprintf(buf, 12, "%d\n", defs.boottime);
 421 }
 422 
 423 /**
 424  * boottime_set - Set function for sysfs attribute boottime
 425  * @dev: the &struct device
 426  * @attr: device attributes
 427  * @buf: buffer that contains new attribute value
 428  * @count: size of buffer
 429  */
 430 static ssize_t boottime_set(struct device *dev,
 431                 struct device_attribute *attr, const char *buf, size_t count)
 432 {
 433         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 434         struct cmd_ds_mesh_config cmd;
 435         uint32_t datum;
 436         int ret;
 437 
 438         memset(&cmd, 0, sizeof(cmd));
 439         ret = sscanf(buf, "%d", &datum);
 440         if ((ret != 1) || (datum > 255))
 441                 return -EINVAL;
 442 
 443         /* A too small boot time will result in the device booting into
 444          * standalone (no-host) mode before the host can take control of it,
 445          * so the change will be hard to revert.  This may be a desired
 446          * feature (e.g to configure a very fast boot time for devices that
 447          * will not be attached to a host), but dangerous.  So I'm enforcing a
 448          * lower limit of 20 seconds:  remove and recompile the driver if this
 449          * does not work for you.
 450          */
 451         datum = (datum < 20) ? 20 : datum;
 452         cmd.data[0] = datum;
 453         cmd.length = cpu_to_le16(sizeof(uint8_t));
 454         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 455                                    CMD_TYPE_MESH_SET_BOOTTIME);
 456         if (ret)
 457                 return ret;
 458 
 459         return strlen(buf);
 460 }
 461 
 462 /**
 463  * channel_get - Get function for sysfs attribute channel
 464  * @dev: the &struct device
 465  * @attr: device attributes
 466  * @buf: buffer where data will be returned
 467  */
 468 static ssize_t channel_get(struct device *dev,
 469                            struct device_attribute *attr, char *buf)
 470 {
 471         struct mrvl_mesh_defaults defs;
 472         int ret;
 473 
 474         ret = mesh_get_default_parameters(dev, &defs);
 475 
 476         if (ret)
 477                 return ret;
 478 
 479         return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
 480 }
 481 
 482 /**
 483  * channel_set - Set function for sysfs attribute channel
 484  * @dev: the &struct device
 485  * @attr: device attributes
 486  * @buf: buffer that contains new attribute value
 487  * @count: size of buffer
 488  */
 489 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
 490                            const char *buf, size_t count)
 491 {
 492         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 493         struct cmd_ds_mesh_config cmd;
 494         uint32_t datum;
 495         int ret;
 496 
 497         memset(&cmd, 0, sizeof(cmd));
 498         ret = sscanf(buf, "%d", &datum);
 499         if (ret != 1 || datum < 1 || datum > 11)
 500                 return -EINVAL;
 501 
 502         *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
 503         cmd.length = cpu_to_le16(sizeof(uint16_t));
 504         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 505                                    CMD_TYPE_MESH_SET_DEF_CHANNEL);
 506         if (ret)
 507                 return ret;
 508 
 509         return strlen(buf);
 510 }
 511 
 512 /**
 513  * mesh_id_get - Get function for sysfs attribute mesh_id
 514  * @dev: the &struct device
 515  * @attr: device attributes
 516  * @buf: buffer where data will be returned
 517  */
 518 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
 519                            char *buf)
 520 {
 521         struct mrvl_mesh_defaults defs;
 522         int ret;
 523 
 524         ret = mesh_get_default_parameters(dev, &defs);
 525 
 526         if (ret)
 527                 return ret;
 528 
 529         if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
 530                 dev_err(dev, "inconsistent mesh ID length\n");
 531                 defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
 532         }
 533 
 534         memcpy(buf, defs.meshie.val.mesh_id, defs.meshie.val.mesh_id_len);
 535         buf[defs.meshie.val.mesh_id_len] = '\n';
 536         buf[defs.meshie.val.mesh_id_len + 1] = '\0';
 537 
 538         return defs.meshie.val.mesh_id_len + 1;
 539 }
 540 
 541 /**
 542  * mesh_id_set - Set function for sysfs attribute mesh_id
 543  * @dev: the &struct device
 544  * @attr: device attributes
 545  * @buf: buffer that contains new attribute value
 546  * @count: size of buffer
 547  */
 548 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
 549                            const char *buf, size_t count)
 550 {
 551         struct cmd_ds_mesh_config cmd;
 552         struct mrvl_mesh_defaults defs;
 553         struct mrvl_meshie *ie;
 554         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 555         int len;
 556         int ret;
 557 
 558         if (count < 2 || count > IEEE80211_MAX_SSID_LEN + 1)
 559                 return -EINVAL;
 560 
 561         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
 562         ie = (struct mrvl_meshie *) &cmd.data[0];
 563 
 564         /* fetch all other Information Element parameters */
 565         ret = mesh_get_default_parameters(dev, &defs);
 566 
 567         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
 568 
 569         /* transfer IE elements */
 570         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
 571 
 572         len = count - 1;
 573         memcpy(ie->val.mesh_id, buf, len);
 574         /* SSID len */
 575         ie->val.mesh_id_len = len;
 576         /* IE len */
 577         ie->len = sizeof(struct mrvl_meshie_val) - IEEE80211_MAX_SSID_LEN + len;
 578 
 579         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 580                                    CMD_TYPE_MESH_SET_MESH_IE);
 581         if (ret)
 582                 return ret;
 583 
 584         return strlen(buf);
 585 }
 586 
 587 /**
 588  * protocol_id_get - Get function for sysfs attribute protocol_id
 589  * @dev: the &struct device
 590  * @attr: device attributes
 591  * @buf: buffer where data will be returned
 592  */
 593 static ssize_t protocol_id_get(struct device *dev,
 594                                struct device_attribute *attr, char *buf)
 595 {
 596         struct mrvl_mesh_defaults defs;
 597         int ret;
 598 
 599         ret = mesh_get_default_parameters(dev, &defs);
 600 
 601         if (ret)
 602                 return ret;
 603 
 604         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
 605 }
 606 
 607 /**
 608  * protocol_id_set - Set function for sysfs attribute protocol_id
 609  * @dev: the &struct device
 610  * @attr: device attributes
 611  * @buf: buffer that contains new attribute value
 612  * @count: size of buffer
 613  */
 614 static ssize_t protocol_id_set(struct device *dev,
 615                 struct device_attribute *attr, const char *buf, size_t count)
 616 {
 617         struct cmd_ds_mesh_config cmd;
 618         struct mrvl_mesh_defaults defs;
 619         struct mrvl_meshie *ie;
 620         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 621         uint32_t datum;
 622         int ret;
 623 
 624         memset(&cmd, 0, sizeof(cmd));
 625         ret = sscanf(buf, "%d", &datum);
 626         if ((ret != 1) || (datum > 255))
 627                 return -EINVAL;
 628 
 629         /* fetch all other Information Element parameters */
 630         ret = mesh_get_default_parameters(dev, &defs);
 631 
 632         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
 633 
 634         /* transfer IE elements */
 635         ie = (struct mrvl_meshie *) &cmd.data[0];
 636         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
 637         /* update protocol id */
 638         ie->val.active_protocol_id = datum;
 639 
 640         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 641                                    CMD_TYPE_MESH_SET_MESH_IE);
 642         if (ret)
 643                 return ret;
 644 
 645         return strlen(buf);
 646 }
 647 
 648 /**
 649  * metric_id_get - Get function for sysfs attribute metric_id
 650  * @dev: the &struct device
 651  * @attr: device attributes
 652  * @buf: buffer where data will be returned
 653  */
 654 static ssize_t metric_id_get(struct device *dev,
 655                 struct device_attribute *attr, char *buf)
 656 {
 657         struct mrvl_mesh_defaults defs;
 658         int ret;
 659 
 660         ret = mesh_get_default_parameters(dev, &defs);
 661 
 662         if (ret)
 663                 return ret;
 664 
 665         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
 666 }
 667 
 668 /**
 669  * metric_id_set - Set function for sysfs attribute metric_id
 670  * @dev: the &struct device
 671  * @attr: device attributes
 672  * @buf: buffer that contains new attribute value
 673  * @count: size of buffer
 674  */
 675 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
 676                              const char *buf, size_t count)
 677 {
 678         struct cmd_ds_mesh_config cmd;
 679         struct mrvl_mesh_defaults defs;
 680         struct mrvl_meshie *ie;
 681         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 682         uint32_t datum;
 683         int ret;
 684 
 685         memset(&cmd, 0, sizeof(cmd));
 686         ret = sscanf(buf, "%d", &datum);
 687         if ((ret != 1) || (datum > 255))
 688                 return -EINVAL;
 689 
 690         /* fetch all other Information Element parameters */
 691         ret = mesh_get_default_parameters(dev, &defs);
 692 
 693         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
 694 
 695         /* transfer IE elements */
 696         ie = (struct mrvl_meshie *) &cmd.data[0];
 697         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
 698         /* update metric id */
 699         ie->val.active_metric_id = datum;
 700 
 701         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 702                                    CMD_TYPE_MESH_SET_MESH_IE);
 703         if (ret)
 704                 return ret;
 705 
 706         return strlen(buf);
 707 }
 708 
 709 /**
 710  * capability_get - Get function for sysfs attribute capability
 711  * @dev: the &struct device
 712  * @attr: device attributes
 713  * @buf: buffer where data will be returned
 714  */
 715 static ssize_t capability_get(struct device *dev,
 716                 struct device_attribute *attr, char *buf)
 717 {
 718         struct mrvl_mesh_defaults defs;
 719         int ret;
 720 
 721         ret = mesh_get_default_parameters(dev, &defs);
 722 
 723         if (ret)
 724                 return ret;
 725 
 726         return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
 727 }
 728 
 729 /**
 730  * capability_set - Set function for sysfs attribute capability
 731  * @dev: the &struct device
 732  * @attr: device attributes
 733  * @buf: buffer that contains new attribute value
 734  * @count: size of buffer
 735  */
 736 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
 737                               const char *buf, size_t count)
 738 {
 739         struct cmd_ds_mesh_config cmd;
 740         struct mrvl_mesh_defaults defs;
 741         struct mrvl_meshie *ie;
 742         struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 743         uint32_t datum;
 744         int ret;
 745 
 746         memset(&cmd, 0, sizeof(cmd));
 747         ret = sscanf(buf, "%d", &datum);
 748         if ((ret != 1) || (datum > 255))
 749                 return -EINVAL;
 750 
 751         /* fetch all other Information Element parameters */
 752         ret = mesh_get_default_parameters(dev, &defs);
 753 
 754         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
 755 
 756         /* transfer IE elements */
 757         ie = (struct mrvl_meshie *) &cmd.data[0];
 758         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
 759         /* update value */
 760         ie->val.mesh_capability = datum;
 761 
 762         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
 763                                    CMD_TYPE_MESH_SET_MESH_IE);
 764         if (ret)
 765                 return ret;
 766 
 767         return strlen(buf);
 768 }
 769 
 770 
 771 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
 772 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
 773 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
 774 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
 775 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
 776 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
 777 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
 778 
 779 static struct attribute *boot_opts_attrs[] = {
 780         &dev_attr_bootflag.attr,
 781         &dev_attr_boottime.attr,
 782         &dev_attr_channel.attr,
 783         NULL
 784 };
 785 
 786 static const struct attribute_group boot_opts_group = {
 787         .name = "boot_options",
 788         .attrs = boot_opts_attrs,
 789 };
 790 
 791 static struct attribute *mesh_ie_attrs[] = {
 792         &dev_attr_mesh_id.attr,
 793         &dev_attr_protocol_id.attr,
 794         &dev_attr_metric_id.attr,
 795         &dev_attr_capability.attr,
 796         NULL
 797 };
 798 
 799 static const struct attribute_group mesh_ie_group = {
 800         .name = "mesh_ie",
 801         .attrs = mesh_ie_attrs,
 802 };
 803 
 804 static void lbs_persist_config_init(struct net_device *dev)
 805 {
 806         int ret;
 807         ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
 808         if (ret)
 809                 pr_err("failed to create boot_opts_group.\n");
 810 
 811         ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
 812         if (ret)
 813                 pr_err("failed to create mesh_ie_group.\n");
 814 }
 815 
 816 static void lbs_persist_config_remove(struct net_device *dev)
 817 {
 818         sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
 819         sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
 820 }
 821 
 822 
 823 /***************************************************************************
 824  * Initializing and starting, stopping mesh
 825  */
 826 
 827 /*
 828  * Check mesh FW version and appropriately send the mesh start
 829  * command
 830  */
 831 int lbs_init_mesh(struct lbs_private *priv)
 832 {
 833         int ret = 0;
 834 
 835         /* Determine mesh_fw_ver from fwrelease and fwcapinfo */
 836         /* 5.0.16p0 9.0.0.p0 is known to NOT support any mesh */
 837         /* 5.110.22 have mesh command with 0xa3 command id */
 838         /* 10.0.0.p0 FW brings in mesh config command with different id */
 839         /* Check FW version MSB and initialize mesh_fw_ver */
 840         if (MRVL_FW_MAJOR_REV(priv->fwrelease) == MRVL_FW_V5) {
 841                 /* Enable mesh, if supported, and work out which TLV it uses.
 842                    0x100 + 291 is an unofficial value used in 5.110.20.pXX
 843                    0x100 + 37 is the official value used in 5.110.21.pXX
 844                    but we check them in that order because 20.pXX doesn't
 845                    give an error -- it just silently fails. */
 846 
 847                 /* 5.110.20.pXX firmware will fail the command if the channel
 848                    doesn't match the existing channel. But only if the TLV
 849                    is correct. If the channel is wrong, _BOTH_ versions will
 850                    give an error to 0x100+291, and allow 0x100+37 to succeed.
 851                    It's just that 5.110.20.pXX will not have done anything
 852                    useful */
 853 
 854                 priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID;
 855                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) {
 856                         priv->mesh_tlv = TLV_TYPE_MESH_ID;
 857                         if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
 858                                 priv->mesh_tlv = 0;
 859                 }
 860         } else
 861         if ((MRVL_FW_MAJOR_REV(priv->fwrelease) >= MRVL_FW_V10) &&
 862                 (priv->fwcapinfo & MESH_CAPINFO_ENABLE_MASK)) {
 863                 /* 10.0.0.pXX new firmwares should succeed with TLV
 864                  * 0x100+37; Do not invoke command with old TLV.
 865                  */
 866                 priv->mesh_tlv = TLV_TYPE_MESH_ID;
 867                 if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1))
 868                         priv->mesh_tlv = 0;
 869         }
 870 
 871         /* Stop meshing until interface is brought up */
 872         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1);
 873 
 874         return ret;
 875 }
 876 
 877 void lbs_start_mesh(struct lbs_private *priv)
 878 {
 879         lbs_add_mesh(priv);
 880 
 881         if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh))
 882                 netdev_err(priv->dev, "cannot register lbs_mesh attribute\n");
 883 }
 884 
 885 int lbs_deinit_mesh(struct lbs_private *priv)
 886 {
 887         struct net_device *dev = priv->dev;
 888         int ret = 0;
 889 
 890         if (priv->mesh_tlv) {
 891                 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
 892                 ret = 1;
 893         }
 894 
 895         return ret;
 896 }
 897 
 898 
 899 /**
 900  * lbs_mesh_stop - close the mshX interface
 901  *
 902  * @dev:        A pointer to &net_device structure
 903  * returns:     0
 904  */
 905 static int lbs_mesh_stop(struct net_device *dev)
 906 {
 907         struct lbs_private *priv = dev->ml_priv;
 908 
 909         lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP,
 910                 lbs_mesh_get_channel(priv));
 911 
 912         spin_lock_irq(&priv->driver_lock);
 913 
 914         netif_stop_queue(dev);
 915         netif_carrier_off(dev);
 916 
 917         spin_unlock_irq(&priv->driver_lock);
 918 
 919         lbs_update_mcast(priv);
 920         if (!lbs_iface_active(priv))
 921                 lbs_stop_iface(priv);
 922 
 923         return 0;
 924 }
 925 
 926 /**
 927  * lbs_mesh_dev_open - open the mshX interface
 928  *
 929  * @dev:        A pointer to &net_device structure
 930  * returns:     0 or -EBUSY if monitor mode active
 931  */
 932 static int lbs_mesh_dev_open(struct net_device *dev)
 933 {
 934         struct lbs_private *priv = dev->ml_priv;
 935         int ret = 0;
 936 
 937         if (!priv->iface_running) {
 938                 ret = lbs_start_iface(priv);
 939                 if (ret)
 940                         goto out;
 941         }
 942 
 943         spin_lock_irq(&priv->driver_lock);
 944 
 945         if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {
 946                 ret = -EBUSY;
 947                 spin_unlock_irq(&priv->driver_lock);
 948                 goto out;
 949         }
 950 
 951         netif_carrier_on(dev);
 952 
 953         if (!priv->tx_pending_len)
 954                 netif_wake_queue(dev);
 955 
 956         spin_unlock_irq(&priv->driver_lock);
 957 
 958         ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,
 959                 lbs_mesh_get_channel(priv));
 960 
 961 out:
 962         return ret;
 963 }
 964 
 965 static const struct net_device_ops mesh_netdev_ops = {
 966         .ndo_open               = lbs_mesh_dev_open,
 967         .ndo_stop               = lbs_mesh_stop,
 968         .ndo_start_xmit         = lbs_hard_start_xmit,
 969         .ndo_set_mac_address    = lbs_set_mac_address,
 970         .ndo_set_rx_mode        = lbs_set_multicast_list,
 971 };
 972 
 973 /**
 974  * lbs_add_mesh - add mshX interface
 975  *
 976  * @priv:       A pointer to the &struct lbs_private structure
 977  * returns:     0 if successful, -X otherwise
 978  */
 979 static int lbs_add_mesh(struct lbs_private *priv)
 980 {
 981         struct net_device *mesh_dev = NULL;
 982         struct wireless_dev *mesh_wdev;
 983         int ret = 0;
 984 
 985         /* Allocate a virtual mesh device */
 986         mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
 987         if (!mesh_wdev) {
 988                 lbs_deb_mesh("init mshX wireless device failed\n");
 989                 ret = -ENOMEM;
 990                 goto done;
 991         }
 992 
 993         mesh_dev = alloc_netdev(0, "msh%d", NET_NAME_UNKNOWN, ether_setup);
 994         if (!mesh_dev) {
 995                 lbs_deb_mesh("init mshX device failed\n");
 996                 ret = -ENOMEM;
 997                 goto err_free_wdev;
 998         }
 999 
1000         mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT;
1001         mesh_wdev->wiphy = priv->wdev->wiphy;
1002 
1003         if (priv->mesh_tlv) {
1004                 sprintf(mesh_wdev->ssid, "mesh");
1005                 mesh_wdev->mesh_id_up_len = 4;
1006                 ret = 1;
1007         }
1008 
1009         mesh_wdev->netdev = mesh_dev;
1010 
1011         mesh_dev->ml_priv = priv;
1012         mesh_dev->ieee80211_ptr = mesh_wdev;
1013         priv->mesh_dev = mesh_dev;
1014 
1015         mesh_dev->netdev_ops = &mesh_netdev_ops;
1016         mesh_dev->ethtool_ops = &lbs_ethtool_ops;
1017         eth_hw_addr_inherit(mesh_dev, priv->dev);
1018 
1019         SET_NETDEV_DEV(priv->mesh_dev, priv->dev->dev.parent);
1020 
1021         mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
1022         /* Register virtual mesh interface */
1023         ret = register_netdev(mesh_dev);
1024         if (ret) {
1025                 pr_err("cannot register mshX virtual interface\n");
1026                 goto err_free_netdev;
1027         }
1028 
1029         ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1030         if (ret)
1031                 goto err_unregister;
1032 
1033         lbs_persist_config_init(mesh_dev);
1034 
1035         /* Everything successful */
1036         ret = 0;
1037         goto done;
1038 
1039 err_unregister:
1040         unregister_netdev(mesh_dev);
1041 
1042 err_free_netdev:
1043         free_netdev(mesh_dev);
1044 
1045 err_free_wdev:
1046         kfree(mesh_wdev);
1047 
1048 done:
1049         return ret;
1050 }
1051 
1052 void lbs_remove_mesh(struct lbs_private *priv)
1053 {
1054         struct net_device *mesh_dev;
1055 
1056         mesh_dev = priv->mesh_dev;
1057         if (!mesh_dev)
1058                 return;
1059 
1060         netif_stop_queue(mesh_dev);
1061         netif_carrier_off(mesh_dev);
1062         sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1063         lbs_persist_config_remove(mesh_dev);
1064         unregister_netdev(mesh_dev);
1065         priv->mesh_dev = NULL;
1066         kfree(mesh_dev->ieee80211_ptr);
1067         free_netdev(mesh_dev);
1068 }
1069 
1070 
1071 /***************************************************************************
1072  * Sending and receiving
1073  */
1074 struct net_device *lbs_mesh_set_dev(struct lbs_private *priv,
1075         struct net_device *dev, struct rxpd *rxpd)
1076 {
1077         if (priv->mesh_dev) {
1078                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID) {
1079                         if (rxpd->rx_control & RxPD_MESH_FRAME)
1080                                 dev = priv->mesh_dev;
1081                 } else if (priv->mesh_tlv == TLV_TYPE_MESH_ID) {
1082                         if (rxpd->u.bss.bss_num == MESH_IFACE_ID)
1083                                 dev = priv->mesh_dev;
1084                 }
1085         }
1086         return dev;
1087 }
1088 
1089 
1090 void lbs_mesh_set_txpd(struct lbs_private *priv,
1091         struct net_device *dev, struct txpd *txpd)
1092 {
1093         if (dev == priv->mesh_dev) {
1094                 if (priv->mesh_tlv == TLV_TYPE_OLD_MESH_ID)
1095                         txpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
1096                 else if (priv->mesh_tlv == TLV_TYPE_MESH_ID)
1097                         txpd->u.bss.bss_num = MESH_IFACE_ID;
1098         }
1099 }
1100 
1101 
1102 /***************************************************************************
1103  * Ethtool related
1104  */
1105 
1106 static const char mesh_stat_strings[MESH_STATS_NUM][ETH_GSTRING_LEN] = {
1107         "drop_duplicate_bcast",
1108         "drop_ttl_zero",
1109         "drop_no_fwd_route",
1110         "drop_no_buffers",
1111         "fwded_unicast_cnt",
1112         "fwded_bcast_cnt",
1113         "drop_blind_table",
1114         "tx_failed_cnt"
1115 };
1116 
1117 void lbs_mesh_ethtool_get_stats(struct net_device *dev,
1118         struct ethtool_stats *stats, uint64_t *data)
1119 {
1120         struct lbs_private *priv = dev->ml_priv;
1121         struct cmd_ds_mesh_access mesh_access;
1122         int ret;
1123 
1124         /* Get Mesh Statistics */
1125         ret = lbs_mesh_access(priv, CMD_ACT_MESH_GET_STATS, &mesh_access);
1126 
1127         if (ret) {
1128                 memset(data, 0, MESH_STATS_NUM*(sizeof(uint64_t)));
1129                 return;
1130         }
1131 
1132         priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
1133         priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
1134         priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
1135         priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
1136         priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
1137         priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
1138         priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
1139         priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
1140 
1141         data[0] = priv->mstats.fwd_drop_rbt;
1142         data[1] = priv->mstats.fwd_drop_ttl;
1143         data[2] = priv->mstats.fwd_drop_noroute;
1144         data[3] = priv->mstats.fwd_drop_nobuf;
1145         data[4] = priv->mstats.fwd_unicast_cnt;
1146         data[5] = priv->mstats.fwd_bcast_cnt;
1147         data[6] = priv->mstats.drop_blind;
1148         data[7] = priv->mstats.tx_failed_cnt;
1149 }
1150 
1151 int lbs_mesh_ethtool_get_sset_count(struct net_device *dev, int sset)
1152 {
1153         struct lbs_private *priv = dev->ml_priv;
1154 
1155         if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
1156                 return MESH_STATS_NUM;
1157 
1158         return -EOPNOTSUPP;
1159 }
1160 
1161 void lbs_mesh_ethtool_get_strings(struct net_device *dev,
1162         uint32_t stringset, uint8_t *s)
1163 {
1164         switch (stringset) {
1165         case ETH_SS_STATS:
1166                 memcpy(s, mesh_stat_strings, sizeof(mesh_stat_strings));
1167                 break;
1168         }
1169 }

/* [<][>][^][v][top][bottom][index][help] */