mesh.c 34 KB

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