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