sysfs.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. /*
  2. * WiMedia Logical Link Control Protocol (WLP)
  3. * sysfs functions
  4. *
  5. * Copyright (C) 2007 Intel Corporation
  6. * Reinette Chatre <reinette.chatre@intel.com>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License version
  10. * 2 as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20. * 02110-1301, USA.
  21. *
  22. *
  23. * FIXME: Docs
  24. *
  25. */
  26. #include <linux/wlp.h>
  27. #include "wlp-internal.h"
  28. static
  29. size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
  30. struct wlp_wssid_e *wssid_e)
  31. {
  32. size_t used = 0;
  33. used += scnprintf(buf, bufsize, " WSS: ");
  34. used += wlp_wss_uuid_print(buf + used, bufsize - used,
  35. &wssid_e->wssid);
  36. if (wssid_e->info != NULL) {
  37. used += scnprintf(buf + used, bufsize - used, " ");
  38. used += uwb_mac_addr_print(buf + used, bufsize - used,
  39. &wssid_e->info->bcast);
  40. used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
  41. wssid_e->info->accept_enroll,
  42. wssid_e->info->sec_status,
  43. wssid_e->info->name);
  44. }
  45. return used;
  46. }
  47. /**
  48. * Print out information learned from neighbor discovery
  49. *
  50. * Some fields being printed may not be included in the device discovery
  51. * information (it is not mandatory). We are thus careful how the
  52. * information is printed to ensure it is clear to the user what field is
  53. * being referenced.
  54. * The information being printed is for one time use - temporary storage is
  55. * cleaned after it is printed.
  56. *
  57. * Ideally sysfs output should be on one line. The information printed here
  58. * contain a few strings so it will be hard to parse if they are all
  59. * printed on the same line - without agreeing on a standard field
  60. * separator.
  61. */
  62. static
  63. ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
  64. size_t bufsize)
  65. {
  66. size_t used = 0;
  67. struct wlp_neighbor_e *neighb;
  68. struct wlp_wssid_e *wssid_e;
  69. mutex_lock(&wlp->nbmutex);
  70. used = scnprintf(buf, bufsize, "#Neighbor information\n"
  71. "#uuid dev_addr\n"
  72. "# Device Name:\n# Model Name:\n# Manufacturer:\n"
  73. "# Model Nr:\n# Serial:\n"
  74. "# Pri Dev type: CategoryID OUI OUISubdiv "
  75. "SubcategoryID\n"
  76. "# WSS: WSSID WSS_name accept_enroll sec_status "
  77. "bcast\n"
  78. "# WSS: WSSID WSS_name accept_enroll sec_status "
  79. "bcast\n\n");
  80. list_for_each_entry(neighb, &wlp->neighbors, node) {
  81. if (bufsize - used <= 0)
  82. goto out;
  83. used += wlp_wss_uuid_print(buf + used, bufsize - used,
  84. &neighb->uuid);
  85. buf[used++] = ' ';
  86. used += uwb_dev_addr_print(buf + used, bufsize - used,
  87. &neighb->uwb_dev->dev_addr);
  88. if (neighb->info != NULL)
  89. used += scnprintf(buf + used, bufsize - used,
  90. "\n Device Name: %s\n"
  91. " Model Name: %s\n"
  92. " Manufacturer:%s \n"
  93. " Model Nr: %s\n"
  94. " Serial: %s\n"
  95. " Pri Dev type: "
  96. "%u %02x:%02x:%02x %u %u\n",
  97. neighb->info->name,
  98. neighb->info->model_name,
  99. neighb->info->manufacturer,
  100. neighb->info->model_nr,
  101. neighb->info->serial,
  102. neighb->info->prim_dev_type.category,
  103. neighb->info->prim_dev_type.OUI[0],
  104. neighb->info->prim_dev_type.OUI[1],
  105. neighb->info->prim_dev_type.OUI[2],
  106. neighb->info->prim_dev_type.OUIsubdiv,
  107. neighb->info->prim_dev_type.subID);
  108. list_for_each_entry(wssid_e, &neighb->wssid, node) {
  109. used += wlp_wss_wssid_e_print(buf + used,
  110. bufsize - used,
  111. wssid_e);
  112. }
  113. buf[used++] = '\n';
  114. wlp_remove_neighbor_tmp_info(neighb);
  115. }
  116. out:
  117. mutex_unlock(&wlp->nbmutex);
  118. return used;
  119. }
  120. /**
  121. * Show properties of all WSS in neighborhood.
  122. *
  123. * Will trigger a complete discovery of WSS activated by this device and
  124. * its neighbors.
  125. */
  126. ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
  127. {
  128. wlp_discover(wlp);
  129. return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
  130. }
  131. EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
  132. static
  133. ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
  134. size_t bufsize)
  135. {
  136. ssize_t result;
  137. result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
  138. result += scnprintf(buf + result, bufsize - result, " ");
  139. result += uwb_mac_addr_print(buf + result, bufsize - result,
  140. &wss->bcast);
  141. result += scnprintf(buf + result, bufsize - result,
  142. " 0x%02x %u ", wss->hash, wss->secure_status);
  143. result += wlp_wss_key_print(buf + result, bufsize - result,
  144. wss->master_key);
  145. result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
  146. wss->tag);
  147. result += uwb_mac_addr_print(buf + result, bufsize - result,
  148. &wss->virtual_addr);
  149. result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
  150. result += scnprintf(buf + result, bufsize - result,
  151. "\n\n#WSSID\n#WSS broadcast address\n"
  152. "#WSS hash\n#WSS secure status\n"
  153. "#WSS master key\n#WSS local tag\n"
  154. "#WSS local virtual EUI-48\n#WSS name\n");
  155. return result;
  156. }
  157. /**
  158. * Show which WSS is activated.
  159. */
  160. ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
  161. {
  162. int result = 0;
  163. if (mutex_lock_interruptible(&wss->mutex))
  164. goto out;
  165. if (wss->state >= WLP_WSS_STATE_ACTIVE)
  166. result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
  167. else
  168. result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
  169. result += scnprintf(buf + result, PAGE_SIZE - result,
  170. "\n\n"
  171. "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
  172. "NAME #create new WSS\n"
  173. "# echo WSSID [DEV ADDR] #enroll in and activate "
  174. "existing WSS, can request registrar\n"
  175. "#\n"
  176. "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
  177. "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
  178. "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
  179. "# NAME is the text string identifying the WSS\n"
  180. "# DEV ADDR is the device address of neighbor "
  181. "that should be registrar. Eg. 32:AB\n");
  182. mutex_unlock(&wss->mutex);
  183. out:
  184. return result;
  185. }
  186. EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
  187. /**
  188. * Create/activate a new WSS or enroll/activate in neighboring WSS
  189. *
  190. * The user can provide the WSSID of a WSS in which it wants to enroll.
  191. * Only the WSSID is necessary if the WSS have been discovered before. If
  192. * the WSS has not been discovered before, or the user wants to use a
  193. * particular neighbor as its registrar, then the user can also provide a
  194. * device address or the neighbor that will be used as registrar.
  195. *
  196. * A new WSS is created when the user provides a WSSID, secure status, and
  197. * WSS name.
  198. */
  199. ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
  200. const char *buf, size_t size)
  201. {
  202. ssize_t result = -EINVAL;
  203. struct wlp_uuid wssid;
  204. struct uwb_dev_addr dev;
  205. struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
  206. char name[65];
  207. unsigned sec_status, accept;
  208. memset(name, 0, sizeof(name));
  209. result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
  210. "%02hhx %02hhx %02hhx %02hhx "
  211. "%02hhx %02hhx %02hhx %02hhx "
  212. "%02hhx %02hhx %02hhx %02hhx "
  213. "%02hhx:%02hhx",
  214. &wssid.data[0] , &wssid.data[1],
  215. &wssid.data[2] , &wssid.data[3],
  216. &wssid.data[4] , &wssid.data[5],
  217. &wssid.data[6] , &wssid.data[7],
  218. &wssid.data[8] , &wssid.data[9],
  219. &wssid.data[10], &wssid.data[11],
  220. &wssid.data[12], &wssid.data[13],
  221. &wssid.data[14], &wssid.data[15],
  222. &dev.data[1], &dev.data[0]);
  223. if (result == 16 || result == 17) {
  224. result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
  225. "%02hhx %02hhx %02hhx %02hhx "
  226. "%02hhx %02hhx %02hhx %02hhx "
  227. "%02hhx %02hhx %02hhx %02hhx "
  228. "%u %u %64c",
  229. &wssid.data[0] , &wssid.data[1],
  230. &wssid.data[2] , &wssid.data[3],
  231. &wssid.data[4] , &wssid.data[5],
  232. &wssid.data[6] , &wssid.data[7],
  233. &wssid.data[8] , &wssid.data[9],
  234. &wssid.data[10], &wssid.data[11],
  235. &wssid.data[12], &wssid.data[13],
  236. &wssid.data[14], &wssid.data[15],
  237. &sec_status, &accept, name);
  238. if (result == 16)
  239. result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
  240. else if (result == 19) {
  241. sec_status = sec_status == 0 ? 0 : 1;
  242. accept = accept == 0 ? 0 : 1;
  243. /* We read name using %c, so the newline needs to be
  244. * removed */
  245. if (strlen(name) != sizeof(name) - 1)
  246. name[strlen(name) - 1] = '\0';
  247. result = wlp_wss_create_activate(wss, &wssid, name,
  248. sec_status, accept);
  249. } else
  250. result = -EINVAL;
  251. } else if (result == 18)
  252. result = wlp_wss_enroll_activate(wss, &wssid, &dev);
  253. else
  254. result = -EINVAL;
  255. return result < 0 ? result : size;
  256. }
  257. EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
  258. /**
  259. * Show the UUID of this host
  260. */
  261. ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
  262. {
  263. ssize_t result = 0;
  264. mutex_lock(&wlp->mutex);
  265. result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
  266. buf[result++] = '\n';
  267. mutex_unlock(&wlp->mutex);
  268. return result;
  269. }
  270. EXPORT_SYMBOL_GPL(wlp_uuid_show);
  271. /**
  272. * Store a new UUID for this host
  273. *
  274. * According to the spec this should be encoded as an octet string in the
  275. * order the octets are shown in string representation in RFC 4122 (WLP
  276. * 0.99 [Table 6])
  277. *
  278. * We do not check value provided by user.
  279. */
  280. ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
  281. {
  282. ssize_t result;
  283. struct wlp_uuid uuid;
  284. mutex_lock(&wlp->mutex);
  285. result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
  286. "%02hhx %02hhx %02hhx %02hhx "
  287. "%02hhx %02hhx %02hhx %02hhx "
  288. "%02hhx %02hhx %02hhx %02hhx ",
  289. &uuid.data[0] , &uuid.data[1],
  290. &uuid.data[2] , &uuid.data[3],
  291. &uuid.data[4] , &uuid.data[5],
  292. &uuid.data[6] , &uuid.data[7],
  293. &uuid.data[8] , &uuid.data[9],
  294. &uuid.data[10], &uuid.data[11],
  295. &uuid.data[12], &uuid.data[13],
  296. &uuid.data[14], &uuid.data[15]);
  297. if (result != 16) {
  298. result = -EINVAL;
  299. goto error;
  300. }
  301. wlp->uuid = uuid;
  302. error:
  303. mutex_unlock(&wlp->mutex);
  304. return result < 0 ? result : size;
  305. }
  306. EXPORT_SYMBOL_GPL(wlp_uuid_store);
  307. /**
  308. * Show contents of members of device information structure
  309. */
  310. #define wlp_dev_info_show(type) \
  311. ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
  312. { \
  313. ssize_t result = 0; \
  314. mutex_lock(&wlp->mutex); \
  315. if (wlp->dev_info == NULL) { \
  316. result = __wlp_setup_device_info(wlp); \
  317. if (result < 0) \
  318. goto out; \
  319. } \
  320. result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
  321. out: \
  322. mutex_unlock(&wlp->mutex); \
  323. return result; \
  324. } \
  325. EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
  326. wlp_dev_info_show(name)
  327. wlp_dev_info_show(model_name)
  328. wlp_dev_info_show(model_nr)
  329. wlp_dev_info_show(manufacturer)
  330. wlp_dev_info_show(serial)
  331. /**
  332. * Store contents of members of device information structure
  333. */
  334. #define wlp_dev_info_store(type, len) \
  335. ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
  336. { \
  337. ssize_t result; \
  338. char format[10]; \
  339. mutex_lock(&wlp->mutex); \
  340. if (wlp->dev_info == NULL) { \
  341. result = __wlp_alloc_device_info(wlp); \
  342. if (result < 0) \
  343. goto out; \
  344. } \
  345. memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
  346. sprintf(format, "%%%uc", len); \
  347. result = sscanf(buf, format, wlp->dev_info->type); \
  348. out: \
  349. mutex_unlock(&wlp->mutex); \
  350. return result < 0 ? result : size; \
  351. } \
  352. EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
  353. wlp_dev_info_store(name, 32)
  354. wlp_dev_info_store(manufacturer, 64)
  355. wlp_dev_info_store(model_name, 32)
  356. wlp_dev_info_store(model_nr, 32)
  357. wlp_dev_info_store(serial, 32)
  358. static
  359. const char *__wlp_dev_category[] = {
  360. [WLP_DEV_CAT_COMPUTER] = "Computer",
  361. [WLP_DEV_CAT_INPUT] = "Input device",
  362. [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
  363. "Copier",
  364. [WLP_DEV_CAT_CAMERA] = "Camera",
  365. [WLP_DEV_CAT_STORAGE] = "Storage Network",
  366. [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
  367. [WLP_DEV_CAT_DISPLAY] = "Display",
  368. [WLP_DEV_CAT_MULTIM] = "Multimedia device",
  369. [WLP_DEV_CAT_GAMING] = "Gaming device",
  370. [WLP_DEV_CAT_TELEPHONE] = "Telephone",
  371. [WLP_DEV_CAT_OTHER] = "Other",
  372. };
  373. static
  374. const char *wlp_dev_category_str(unsigned cat)
  375. {
  376. if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
  377. || cat == WLP_DEV_CAT_OTHER)
  378. return __wlp_dev_category[cat];
  379. return "unknown category";
  380. }
  381. ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
  382. {
  383. ssize_t result = 0;
  384. mutex_lock(&wlp->mutex);
  385. if (wlp->dev_info == NULL) {
  386. result = __wlp_setup_device_info(wlp);
  387. if (result < 0)
  388. goto out;
  389. }
  390. result = scnprintf(buf, PAGE_SIZE, "%s\n",
  391. wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
  392. out:
  393. mutex_unlock(&wlp->mutex);
  394. return result;
  395. }
  396. EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
  397. ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
  398. size_t size)
  399. {
  400. ssize_t result;
  401. u16 cat;
  402. mutex_lock(&wlp->mutex);
  403. if (wlp->dev_info == NULL) {
  404. result = __wlp_alloc_device_info(wlp);
  405. if (result < 0)
  406. goto out;
  407. }
  408. result = sscanf(buf, "%hu", &cat);
  409. if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
  410. || cat == WLP_DEV_CAT_OTHER)
  411. wlp->dev_info->prim_dev_type.category = cat;
  412. else
  413. result = -EINVAL;
  414. out:
  415. mutex_unlock(&wlp->mutex);
  416. return result < 0 ? result : size;
  417. }
  418. EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
  419. ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
  420. {
  421. ssize_t result = 0;
  422. mutex_lock(&wlp->mutex);
  423. if (wlp->dev_info == NULL) {
  424. result = __wlp_setup_device_info(wlp);
  425. if (result < 0)
  426. goto out;
  427. }
  428. result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
  429. wlp->dev_info->prim_dev_type.OUI[0],
  430. wlp->dev_info->prim_dev_type.OUI[1],
  431. wlp->dev_info->prim_dev_type.OUI[2]);
  432. out:
  433. mutex_unlock(&wlp->mutex);
  434. return result;
  435. }
  436. EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
  437. ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
  438. {
  439. ssize_t result;
  440. u8 OUI[3];
  441. mutex_lock(&wlp->mutex);
  442. if (wlp->dev_info == NULL) {
  443. result = __wlp_alloc_device_info(wlp);
  444. if (result < 0)
  445. goto out;
  446. }
  447. result = sscanf(buf, "%hhx:%hhx:%hhx",
  448. &OUI[0], &OUI[1], &OUI[2]);
  449. if (result != 3) {
  450. result = -EINVAL;
  451. goto out;
  452. } else
  453. memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
  454. out:
  455. mutex_unlock(&wlp->mutex);
  456. return result < 0 ? result : size;
  457. }
  458. EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
  459. ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
  460. {
  461. ssize_t result = 0;
  462. mutex_lock(&wlp->mutex);
  463. if (wlp->dev_info == NULL) {
  464. result = __wlp_setup_device_info(wlp);
  465. if (result < 0)
  466. goto out;
  467. }
  468. result = scnprintf(buf, PAGE_SIZE, "%u\n",
  469. wlp->dev_info->prim_dev_type.OUIsubdiv);
  470. out:
  471. mutex_unlock(&wlp->mutex);
  472. return result;
  473. }
  474. EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
  475. ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
  476. size_t size)
  477. {
  478. ssize_t result;
  479. unsigned sub;
  480. u8 max_sub = ~0;
  481. mutex_lock(&wlp->mutex);
  482. if (wlp->dev_info == NULL) {
  483. result = __wlp_alloc_device_info(wlp);
  484. if (result < 0)
  485. goto out;
  486. }
  487. result = sscanf(buf, "%u", &sub);
  488. if (sub <= max_sub)
  489. wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
  490. else
  491. result = -EINVAL;
  492. out:
  493. mutex_unlock(&wlp->mutex);
  494. return result < 0 ? result : size;
  495. }
  496. EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
  497. ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
  498. {
  499. ssize_t result = 0;
  500. mutex_lock(&wlp->mutex);
  501. if (wlp->dev_info == NULL) {
  502. result = __wlp_setup_device_info(wlp);
  503. if (result < 0)
  504. goto out;
  505. }
  506. result = scnprintf(buf, PAGE_SIZE, "%u\n",
  507. wlp->dev_info->prim_dev_type.subID);
  508. out:
  509. mutex_unlock(&wlp->mutex);
  510. return result;
  511. }
  512. EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
  513. ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
  514. size_t size)
  515. {
  516. ssize_t result;
  517. unsigned sub;
  518. __le16 max_sub = ~0;
  519. mutex_lock(&wlp->mutex);
  520. if (wlp->dev_info == NULL) {
  521. result = __wlp_alloc_device_info(wlp);
  522. if (result < 0)
  523. goto out;
  524. }
  525. result = sscanf(buf, "%u", &sub);
  526. if (sub <= max_sub)
  527. wlp->dev_info->prim_dev_type.subID = sub;
  528. else
  529. result = -EINVAL;
  530. out:
  531. mutex_unlock(&wlp->mutex);
  532. return result < 0 ? result : size;
  533. }
  534. EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
  535. /**
  536. * Subsystem implementation for interaction with individual WSS via sysfs
  537. *
  538. * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
  539. */
  540. #define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
  541. #define attr_to_wlp_wss_attr(_attr) \
  542. container_of(_attr, struct wlp_wss_attribute, attr)
  543. /**
  544. * Sysfs subsystem: forward read calls
  545. *
  546. * Sysfs operation for forwarding read call to the show method of the
  547. * attribute owner
  548. */
  549. static
  550. ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
  551. char *buf)
  552. {
  553. struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
  554. struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
  555. ssize_t ret = -EIO;
  556. if (wss_attr->show)
  557. ret = wss_attr->show(wss, buf);
  558. return ret;
  559. }
  560. /**
  561. * Sysfs subsystem: forward write calls
  562. *
  563. * Sysfs operation for forwarding write call to the store method of the
  564. * attribute owner
  565. */
  566. static
  567. ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
  568. const char *buf, size_t count)
  569. {
  570. struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
  571. struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
  572. ssize_t ret = -EIO;
  573. if (wss_attr->store)
  574. ret = wss_attr->store(wss, buf, count);
  575. return ret;
  576. }
  577. static
  578. struct sysfs_ops wss_sysfs_ops = {
  579. .show = wlp_wss_attr_show,
  580. .store = wlp_wss_attr_store,
  581. };
  582. struct kobj_type wss_ktype = {
  583. .release = wlp_wss_release,
  584. .sysfs_ops = &wss_sysfs_ops,
  585. };
  586. /**
  587. * Sysfs files for individual WSS
  588. */
  589. /**
  590. * Print static properties of this WSS
  591. *
  592. * The name of a WSS may not be null teminated. It's max size is 64 bytes
  593. * so we copy it to a larger array just to make sure we print sane data.
  594. */
  595. static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
  596. {
  597. int result = 0;
  598. if (mutex_lock_interruptible(&wss->mutex))
  599. goto out;
  600. result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
  601. mutex_unlock(&wss->mutex);
  602. out:
  603. return result;
  604. }
  605. WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
  606. /**
  607. * Print all connected members of this WSS
  608. * The EDA cache contains all members of WSS neighborhood.
  609. */
  610. static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
  611. {
  612. struct wlp *wlp = container_of(wss, struct wlp, wss);
  613. return wlp_eda_show(wlp, buf);
  614. }
  615. WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
  616. static
  617. const char *__wlp_strstate[] = {
  618. "none",
  619. "partially enrolled",
  620. "enrolled",
  621. "active",
  622. "connected",
  623. };
  624. static const char *wlp_wss_strstate(unsigned state)
  625. {
  626. if (state >= ARRAY_SIZE(__wlp_strstate))
  627. return "unknown state";
  628. return __wlp_strstate[state];
  629. }
  630. /*
  631. * Print current state of this WSS
  632. */
  633. static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
  634. {
  635. int result = 0;
  636. if (mutex_lock_interruptible(&wss->mutex))
  637. goto out;
  638. result = scnprintf(buf, PAGE_SIZE, "%s\n",
  639. wlp_wss_strstate(wss->state));
  640. mutex_unlock(&wss->mutex);
  641. out:
  642. return result;
  643. }
  644. WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
  645. static
  646. struct attribute *wss_attrs[] = {
  647. &wss_attr_properties.attr,
  648. &wss_attr_members.attr,
  649. &wss_attr_state.attr,
  650. NULL,
  651. };
  652. struct attribute_group wss_attr_group = {
  653. .name = NULL, /* we want them in the same directory */
  654. .attrs = wss_attrs,
  655. };