4 #include "wlp-internal.h"
7 size_t wlp_wss_wssid_e_print(char *buf
, size_t bufsize
,
8 struct wlp_wssid_e
*wssid_e
)
11 used
+= scnprintf(buf
, bufsize
, " WSS: ");
12 used
+= wlp_wss_uuid_print(buf
+ used
, bufsize
- used
,
15 if (wssid_e
->info
!= NULL
) {
16 used
+= scnprintf(buf
+ used
, bufsize
- used
, " ");
17 used
+= uwb_mac_addr_print(buf
+ used
, bufsize
- used
,
18 &wssid_e
->info
->bcast
);
19 used
+= scnprintf(buf
+ used
, bufsize
- used
, " %u %u %s\n",
20 wssid_e
->info
->accept_enroll
,
21 wssid_e
->info
->sec_status
,
28 * Print out information learned from neighbor discovery
30 * Some fields being printed may not be included in the device discovery
31 * information (it is not mandatory). We are thus careful how the
32 * information is printed to ensure it is clear to the user what field is
34 * The information being printed is for one time use - temporary storage is
35 * cleaned after it is printed.
37 * Ideally sysfs output should be on one line. The information printed here
38 * contain a few strings so it will be hard to parse if they are all
39 * printed on the same line - without agreeing on a standard field
43 ssize_t
wlp_wss_neighborhood_print_remove(struct wlp
*wlp
, char *buf
,
47 struct wlp_neighbor_e
*neighb
;
48 struct wlp_wssid_e
*wssid_e
;
50 mutex_lock(&wlp
->nbmutex
);
51 used
= scnprintf(buf
, bufsize
, "#Neighbor information\n"
53 "# Device Name:\n# Model Name:\n# Manufacturer:\n"
54 "# Model Nr:\n# Serial:\n"
55 "# Pri Dev type: CategoryID OUI OUISubdiv "
57 "# WSS: WSSID WSS_name accept_enroll sec_status "
59 "# WSS: WSSID WSS_name accept_enroll sec_status "
61 list_for_each_entry(neighb
, &wlp
->neighbors
, node
) {
62 if (bufsize
- used
<= 0)
64 used
+= wlp_wss_uuid_print(buf
+ used
, bufsize
- used
,
67 used
+= uwb_dev_addr_print(buf
+ used
, bufsize
- used
,
68 &neighb
->uwb_dev
->dev_addr
);
69 if (neighb
->info
!= NULL
)
70 used
+= scnprintf(buf
+ used
, bufsize
- used
,
71 "\n Device Name: %s\n"
77 "%u %02x:%02x:%02x %u %u\n",
79 neighb
->info
->model_name
,
80 neighb
->info
->manufacturer
,
81 neighb
->info
->model_nr
,
83 neighb
->info
->prim_dev_type
.category
,
84 neighb
->info
->prim_dev_type
.OUI
[0],
85 neighb
->info
->prim_dev_type
.OUI
[1],
86 neighb
->info
->prim_dev_type
.OUI
[2],
87 neighb
->info
->prim_dev_type
.OUIsubdiv
,
88 neighb
->info
->prim_dev_type
.subID
);
89 list_for_each_entry(wssid_e
, &neighb
->wssid
, node
) {
90 used
+= wlp_wss_wssid_e_print(buf
+ used
,
95 wlp_remove_neighbor_tmp_info(neighb
);
100 mutex_unlock(&wlp
->nbmutex
);
106 * Show properties of all WSS in neighborhood.
108 * Will trigger a complete discovery of WSS activated by this device and
111 ssize_t
wlp_neighborhood_show(struct wlp
*wlp
, char *buf
)
114 return wlp_wss_neighborhood_print_remove(wlp
, buf
, PAGE_SIZE
);
116 EXPORT_SYMBOL_GPL(wlp_neighborhood_show
);
119 ssize_t
__wlp_wss_properties_show(struct wlp_wss
*wss
, char *buf
,
124 result
= wlp_wss_uuid_print(buf
, bufsize
, &wss
->wssid
);
125 result
+= scnprintf(buf
+ result
, bufsize
- result
, " ");
126 result
+= uwb_mac_addr_print(buf
+ result
, bufsize
- result
,
128 result
+= scnprintf(buf
+ result
, bufsize
- result
,
129 " 0x%02x %u ", wss
->hash
, wss
->secure_status
);
130 result
+= wlp_wss_key_print(buf
+ result
, bufsize
- result
,
132 result
+= scnprintf(buf
+ result
, bufsize
- result
, " 0x%02x ",
134 result
+= uwb_mac_addr_print(buf
+ result
, bufsize
- result
,
136 result
+= scnprintf(buf
+ result
, bufsize
- result
, " %s", wss
->name
);
137 result
+= scnprintf(buf
+ result
, bufsize
- result
,
138 "\n\n#WSSID\n#WSS broadcast address\n"
139 "#WSS hash\n#WSS secure status\n"
140 "#WSS master key\n#WSS local tag\n"
141 "#WSS local virtual EUI-48\n#WSS name\n");
146 * Show which WSS is activated.
148 ssize_t
wlp_wss_activate_show(struct wlp_wss
*wss
, char *buf
)
152 if (mutex_lock_interruptible(&wss
->mutex
))
154 if (wss
->state
>= WLP_WSS_STATE_ACTIVE
)
155 result
= __wlp_wss_properties_show(wss
, buf
, PAGE_SIZE
);
157 result
= scnprintf(buf
, PAGE_SIZE
, "No local WSS active.\n");
158 result
+= scnprintf(buf
+ result
, PAGE_SIZE
- result
,
160 "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
161 "NAME #create new WSS\n"
162 "# echo WSSID [DEV ADDR] #enroll in and activate "
163 "existing WSS, can request registrar\n"
165 "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
166 "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
167 "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
168 "# NAME is the text string identifying the WSS\n"
169 "# DEV ADDR is the device address of neighbor "
170 "that should be registrar. Eg. 32:AB\n");
172 mutex_unlock(&wss
->mutex
);
177 EXPORT_SYMBOL_GPL(wlp_wss_activate_show
);
180 * Create/activate a new WSS or enroll/activate in neighboring WSS
182 * The user can provide the WSSID of a WSS in which it wants to enroll.
183 * Only the WSSID is necessary if the WSS have been discovered before. If
184 * the WSS has not been discovered before, or the user wants to use a
185 * particular neighbor as its registrar, then the user can also provide a
186 * device address or the neighbor that will be used as registrar.
188 * A new WSS is created when the user provides a WSSID, secure status, and
191 ssize_t
wlp_wss_activate_store(struct wlp_wss
*wss
,
192 const char *buf
, size_t size
)
194 ssize_t result
= -EINVAL
;
195 struct wlp_uuid wssid
;
196 struct uwb_dev_addr dev
;
197 struct uwb_dev_addr bcast
= {.data
= {0xff, 0xff} };
199 unsigned sec_status
, accept
;
200 memset(name
, 0, sizeof(name
));
201 result
= sscanf(buf
, "%02hhx %02hhx %02hhx %02hhx "
202 "%02hhx %02hhx %02hhx %02hhx "
203 "%02hhx %02hhx %02hhx %02hhx "
204 "%02hhx %02hhx %02hhx %02hhx "
206 &wssid
.data
[0] , &wssid
.data
[1],
207 &wssid
.data
[2] , &wssid
.data
[3],
208 &wssid
.data
[4] , &wssid
.data
[5],
209 &wssid
.data
[6] , &wssid
.data
[7],
210 &wssid
.data
[8] , &wssid
.data
[9],
211 &wssid
.data
[10], &wssid
.data
[11],
212 &wssid
.data
[12], &wssid
.data
[13],
213 &wssid
.data
[14], &wssid
.data
[15],
214 &dev
.data
[1], &dev
.data
[0]);
215 if (result
== 16 || result
== 17) {
216 result
= sscanf(buf
, "%02hhx %02hhx %02hhx %02hhx "
217 "%02hhx %02hhx %02hhx %02hhx "
218 "%02hhx %02hhx %02hhx %02hhx "
219 "%02hhx %02hhx %02hhx %02hhx "
221 &wssid
.data
[0] , &wssid
.data
[1],
222 &wssid
.data
[2] , &wssid
.data
[3],
223 &wssid
.data
[4] , &wssid
.data
[5],
224 &wssid
.data
[6] , &wssid
.data
[7],
225 &wssid
.data
[8] , &wssid
.data
[9],
226 &wssid
.data
[10], &wssid
.data
[11],
227 &wssid
.data
[12], &wssid
.data
[13],
228 &wssid
.data
[14], &wssid
.data
[15],
229 &sec_status
, &accept
, name
);
231 result
= wlp_wss_enroll_activate(wss
, &wssid
, &bcast
);
232 else if (result
== 19) {
233 sec_status
= sec_status
== 0 ? 0 : 1;
234 accept
= accept
== 0 ? 0 : 1;
235 /* We read name using %c, so the newline needs to be
237 if (strlen(name
) != sizeof(name
) - 1)
238 name
[strlen(name
) - 1] = '\0';
239 result
= wlp_wss_create_activate(wss
, &wssid
, name
,
243 } else if (result
== 18)
244 result
= wlp_wss_enroll_activate(wss
, &wssid
, &dev
);
247 return result
< 0 ? result
: size
;
249 EXPORT_SYMBOL_GPL(wlp_wss_activate_store
);
252 * Show the UUID of this host
254 ssize_t
wlp_uuid_show(struct wlp
*wlp
, char *buf
)
258 mutex_lock(&wlp
->mutex
);
259 result
= wlp_wss_uuid_print(buf
, PAGE_SIZE
, &wlp
->uuid
);
260 buf
[result
++] = '\n';
261 mutex_unlock(&wlp
->mutex
);
264 EXPORT_SYMBOL_GPL(wlp_uuid_show
);
267 * Store a new UUID for this host
269 * According to the spec this should be encoded as an octet string in the
270 * order the octets are shown in string representation in RFC 4122 (WLP
273 * We do not check value provided by user.
275 ssize_t
wlp_uuid_store(struct wlp
*wlp
, const char *buf
, size_t size
)
278 struct wlp_uuid uuid
;
280 mutex_lock(&wlp
->mutex
);
281 result
= sscanf(buf
, "%02hhx %02hhx %02hhx %02hhx "
282 "%02hhx %02hhx %02hhx %02hhx "
283 "%02hhx %02hhx %02hhx %02hhx "
284 "%02hhx %02hhx %02hhx %02hhx ",
285 &uuid
.data
[0] , &uuid
.data
[1],
286 &uuid
.data
[2] , &uuid
.data
[3],
287 &uuid
.data
[4] , &uuid
.data
[5],
288 &uuid
.data
[6] , &uuid
.data
[7],
289 &uuid
.data
[8] , &uuid
.data
[9],
290 &uuid
.data
[10], &uuid
.data
[11],
291 &uuid
.data
[12], &uuid
.data
[13],
292 &uuid
.data
[14], &uuid
.data
[15]);
299 mutex_unlock(&wlp
->mutex
);
300 return result
< 0 ? result
: size
;
302 EXPORT_SYMBOL_GPL(wlp_uuid_store
);
305 * Show contents of members of device information structure
307 #define wlp_dev_info_show(type) \
308 ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
310 ssize_t result = 0; \
311 mutex_lock(&wlp->mutex); \
312 if (wlp->dev_info == NULL) { \
313 result = __wlp_setup_device_info(wlp); \
317 result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
319 mutex_unlock(&wlp->mutex); \
322 EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
324 wlp_dev_info_show(name
)
325 wlp_dev_info_show(model_name
)
326 wlp_dev_info_show(model_nr
)
327 wlp_dev_info_show(manufacturer
)
328 wlp_dev_info_show(serial
)
331 * Store contents of members of device information structure
333 #define wlp_dev_info_store(type, len) \
334 ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
338 mutex_lock(&wlp->mutex); \
339 if (wlp->dev_info == NULL) { \
340 result = __wlp_alloc_device_info(wlp); \
344 memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
345 sprintf(format, "%%%uc", len); \
346 result = sscanf(buf, format, wlp->dev_info->type); \
348 mutex_unlock(&wlp->mutex); \
349 return result < 0 ? result : size; \
351 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)
360 const char *__wlp_dev_category
[] = {
361 [WLP_DEV_CAT_COMPUTER
] = "Computer",
362 [WLP_DEV_CAT_INPUT
] = "Input device",
363 [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER
] = "Printer, scanner, FAX, or "
365 [WLP_DEV_CAT_CAMERA
] = "Camera",
366 [WLP_DEV_CAT_STORAGE
] = "Storage Network",
367 [WLP_DEV_CAT_INFRASTRUCTURE
] = "Infrastructure",
368 [WLP_DEV_CAT_DISPLAY
] = "Display",
369 [WLP_DEV_CAT_MULTIM
] = "Multimedia device",
370 [WLP_DEV_CAT_GAMING
] = "Gaming device",
371 [WLP_DEV_CAT_TELEPHONE
] = "Telephone",
372 [WLP_DEV_CAT_OTHER
] = "Other",
376 const char *wlp_dev_category_str(unsigned cat
)
378 if ((cat
>= WLP_DEV_CAT_COMPUTER
&& cat
<= WLP_DEV_CAT_TELEPHONE
)
379 || cat
== WLP_DEV_CAT_OTHER
)
380 return __wlp_dev_category
[cat
];
381 return "unknown category";
384 ssize_t
wlp_dev_prim_category_show(struct wlp
*wlp
, char *buf
)
387 mutex_lock(&wlp
->mutex
);
388 if (wlp
->dev_info
== NULL
) {
389 result
= __wlp_setup_device_info(wlp
);
393 result
= scnprintf(buf
, PAGE_SIZE
, "%s\n",
394 wlp_dev_category_str(wlp
->dev_info
->prim_dev_type
.category
));
396 mutex_unlock(&wlp
->mutex
);
399 EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show
);
401 ssize_t
wlp_dev_prim_category_store(struct wlp
*wlp
, const char *buf
,
406 mutex_lock(&wlp
->mutex
);
407 if (wlp
->dev_info
== NULL
) {
408 result
= __wlp_alloc_device_info(wlp
);
412 result
= sscanf(buf
, "%hu", &cat
);
413 if ((cat
>= WLP_DEV_CAT_COMPUTER
&& cat
<= WLP_DEV_CAT_TELEPHONE
)
414 || cat
== WLP_DEV_CAT_OTHER
)
415 wlp
->dev_info
->prim_dev_type
.category
= cat
;
419 mutex_unlock(&wlp
->mutex
);
420 return result
< 0 ? result
: size
;
422 EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store
);
424 ssize_t
wlp_dev_prim_OUI_show(struct wlp
*wlp
, char *buf
)
427 mutex_lock(&wlp
->mutex
);
428 if (wlp
->dev_info
== NULL
) {
429 result
= __wlp_setup_device_info(wlp
);
433 result
= scnprintf(buf
, PAGE_SIZE
, "%02x:%02x:%02x\n",
434 wlp
->dev_info
->prim_dev_type
.OUI
[0],
435 wlp
->dev_info
->prim_dev_type
.OUI
[1],
436 wlp
->dev_info
->prim_dev_type
.OUI
[2]);
438 mutex_unlock(&wlp
->mutex
);
441 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show
);
443 ssize_t
wlp_dev_prim_OUI_store(struct wlp
*wlp
, const char *buf
, size_t size
)
447 mutex_lock(&wlp
->mutex
);
448 if (wlp
->dev_info
== NULL
) {
449 result
= __wlp_alloc_device_info(wlp
);
453 result
= sscanf(buf
, "%hhx:%hhx:%hhx",
454 &OUI
[0], &OUI
[1], &OUI
[2]);
459 memcpy(wlp
->dev_info
->prim_dev_type
.OUI
, OUI
, sizeof(OUI
));
461 mutex_unlock(&wlp
->mutex
);
462 return result
< 0 ? result
: size
;
464 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store
);
467 ssize_t
wlp_dev_prim_OUI_sub_show(struct wlp
*wlp
, char *buf
)
470 mutex_lock(&wlp
->mutex
);
471 if (wlp
->dev_info
== NULL
) {
472 result
= __wlp_setup_device_info(wlp
);
476 result
= scnprintf(buf
, PAGE_SIZE
, "%u\n",
477 wlp
->dev_info
->prim_dev_type
.OUIsubdiv
);
479 mutex_unlock(&wlp
->mutex
);
482 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show
);
484 ssize_t
wlp_dev_prim_OUI_sub_store(struct wlp
*wlp
, const char *buf
,
490 mutex_lock(&wlp
->mutex
);
491 if (wlp
->dev_info
== NULL
) {
492 result
= __wlp_alloc_device_info(wlp
);
496 result
= sscanf(buf
, "%u", &sub
);
498 wlp
->dev_info
->prim_dev_type
.OUIsubdiv
= sub
;
502 mutex_unlock(&wlp
->mutex
);
503 return result
< 0 ? result
: size
;
505 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store
);
507 ssize_t
wlp_dev_prim_subcat_show(struct wlp
*wlp
, char *buf
)
510 mutex_lock(&wlp
->mutex
);
511 if (wlp
->dev_info
== NULL
) {
512 result
= __wlp_setup_device_info(wlp
);
516 result
= scnprintf(buf
, PAGE_SIZE
, "%u\n",
517 wlp
->dev_info
->prim_dev_type
.subID
);
519 mutex_unlock(&wlp
->mutex
);
522 EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show
);
524 ssize_t
wlp_dev_prim_subcat_store(struct wlp
*wlp
, const char *buf
,
530 mutex_lock(&wlp
->mutex
);
531 if (wlp
->dev_info
== NULL
) {
532 result
= __wlp_alloc_device_info(wlp
);
536 result
= sscanf(buf
, "%u", &sub
);
538 wlp
->dev_info
->prim_dev_type
.subID
= sub
;
542 mutex_unlock(&wlp
->mutex
);
543 return result
< 0 ? result
: size
;
545 EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store
);
548 * Subsystem implementation for interaction with individual WSS via sysfs
550 * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
553 #define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
554 #define attr_to_wlp_wss_attr(_attr) \
555 container_of(_attr, struct wlp_wss_attribute, attr)
558 * Sysfs subsystem: forward read calls
560 * Sysfs operation for forwarding read call to the show method of the
564 ssize_t
wlp_wss_attr_show(struct kobject
*kobj
, struct attribute
*attr
,
567 struct wlp_wss_attribute
*wss_attr
= attr_to_wlp_wss_attr(attr
);
568 struct wlp_wss
*wss
= kobj_to_wlp_wss(kobj
);
572 ret
= wss_attr
->show(wss
, buf
);
576 * Sysfs subsystem: forward write calls
578 * Sysfs operation for forwarding write call to the store method of the
582 ssize_t
wlp_wss_attr_store(struct kobject
*kobj
, struct attribute
*attr
,
583 const char *buf
, size_t count
)
585 struct wlp_wss_attribute
*wss_attr
= attr_to_wlp_wss_attr(attr
);
586 struct wlp_wss
*wss
= kobj_to_wlp_wss(kobj
);
590 ret
= wss_attr
->store(wss
, buf
, count
);
594 static const struct sysfs_ops wss_sysfs_ops
= {
595 .show
= wlp_wss_attr_show
,
596 .store
= wlp_wss_attr_store
,
599 struct kobj_type wss_ktype
= {
600 .release
= wlp_wss_release
,
601 .sysfs_ops
= &wss_sysfs_ops
,
606 * Sysfs files for individual WSS
610 * Print static properties of this WSS
612 * The name of a WSS may not be null teminated. It's max size is 64 bytes
613 * so we copy it to a larger array just to make sure we print sane data.
615 static ssize_t
wlp_wss_properties_show(struct wlp_wss
*wss
, char *buf
)
619 if (mutex_lock_interruptible(&wss
->mutex
))
621 result
= __wlp_wss_properties_show(wss
, buf
, PAGE_SIZE
);
622 mutex_unlock(&wss
->mutex
);
626 WSS_ATTR(properties
, S_IRUGO
, wlp_wss_properties_show
, NULL
);
629 * Print all connected members of this WSS
630 * The EDA cache contains all members of WSS neighborhood.
632 static ssize_t
wlp_wss_members_show(struct wlp_wss
*wss
, char *buf
)
634 struct wlp
*wlp
= container_of(wss
, struct wlp
, wss
);
635 return wlp_eda_show(wlp
, buf
);
637 WSS_ATTR(members
, S_IRUGO
, wlp_wss_members_show
, NULL
);
640 const char *__wlp_strstate
[] = {
642 "partially enrolled",
648 static const char *wlp_wss_strstate(unsigned state
)
650 if (state
>= ARRAY_SIZE(__wlp_strstate
))
651 return "unknown state";
652 return __wlp_strstate
[state
];
656 * Print current state of this WSS
658 static ssize_t
wlp_wss_state_show(struct wlp_wss
*wss
, char *buf
)
662 if (mutex_lock_interruptible(&wss
->mutex
))
664 result
= scnprintf(buf
, PAGE_SIZE
, "%s\n",
665 wlp_wss_strstate(wss
->state
));
666 mutex_unlock(&wss
->mutex
);
670 WSS_ATTR(state
, S_IRUGO
, wlp_wss_state_show
, NULL
);
674 struct attribute
*wss_attrs
[] = {
675 &wss_attr_properties
.attr
,
676 &wss_attr_members
.attr
,
677 &wss_attr_state
.attr
,
681 struct attribute_group wss_attr_group
= {
682 .name
= NULL
, /* we want them in the same directory */