mesh.c 28 KB

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