2 * WiMedia Logical Link Control Protocol (WLP)
5 * Copyright (C) 2007 Intel Corporation
6 * Reinette Chatre <reinette.chatre@intel.com>
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.
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.
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
27 #include <linux/wlp.h>
28 #include "wlp-internal.h"
31 size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
32 struct wlp_wssid_e *wssid_e)
35 used += scnprintf(buf, bufsize, " WSS: ");
36 used += wlp_wss_uuid_print(buf + used, bufsize - used,
39 if (wssid_e->info != NULL) {
40 used += scnprintf(buf + used, bufsize - used, " ");
41 used += uwb_mac_addr_print(buf + used, bufsize - used,
42 &wssid_e->info->bcast);
43 used += scnprintf(buf + used, bufsize - used, " %u %u %s\n",
44 wssid_e->info->accept_enroll,
45 wssid_e->info->sec_status,
52 * Print out information learned from neighbor discovery
54 * Some fields being printed may not be included in the device discovery
55 * information (it is not mandatory). We are thus careful how the
56 * information is printed to ensure it is clear to the user what field is
58 * The information being printed is for one time use - temporary storage is
59 * cleaned after it is printed.
61 * Ideally sysfs output should be on one line. The information printed here
62 * contain a few strings so it will be hard to parse if they are all
63 * printed on the same line - without agreeing on a standard field
67 ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
71 struct wlp_neighbor_e *neighb;
72 struct wlp_wssid_e *wssid_e;
74 mutex_lock(&wlp->nbmutex);
75 used = scnprintf(buf, bufsize, "#Neighbor information\n"
77 "# Device Name:\n# Model Name:\n# Manufacturer:\n"
78 "# Model Nr:\n# Serial:\n"
79 "# Pri Dev type: CategoryID OUI OUISubdiv "
81 "# WSS: WSSID WSS_name accept_enroll sec_status "
83 "# WSS: WSSID WSS_name accept_enroll sec_status "
85 list_for_each_entry(neighb, &wlp->neighbors, node) {
86 if (bufsize - used <= 0)
88 used += wlp_wss_uuid_print(buf + used, bufsize - used,
91 used += uwb_dev_addr_print(buf + used, bufsize - used,
92 &neighb->uwb_dev->dev_addr);
93 if (neighb->info != NULL)
94 used += scnprintf(buf + used, bufsize - used,
95 "\n Device Name: %s\n"
101 "%u %02x:%02x:%02x %u %u\n",
103 neighb->info->model_name,
104 neighb->info->manufacturer,
105 neighb->info->model_nr,
106 neighb->info->serial,
107 neighb->info->prim_dev_type.category,
108 neighb->info->prim_dev_type.OUI[0],
109 neighb->info->prim_dev_type.OUI[1],
110 neighb->info->prim_dev_type.OUI[2],
111 neighb->info->prim_dev_type.OUIsubdiv,
112 neighb->info->prim_dev_type.subID);
113 list_for_each_entry(wssid_e, &neighb->wssid, node) {
114 used += wlp_wss_wssid_e_print(buf + used,
119 wlp_remove_neighbor_tmp_info(neighb);
124 mutex_unlock(&wlp->nbmutex);
130 * Show properties of all WSS in neighborhood.
132 * Will trigger a complete discovery of WSS activated by this device and
135 ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
138 return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
140 EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
143 ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
148 result = wlp_wss_uuid_print(buf, bufsize, &wss->wssid);
149 result += scnprintf(buf + result, bufsize - result, " ");
150 result += uwb_mac_addr_print(buf + result, bufsize - result,
152 result += scnprintf(buf + result, bufsize - result,
153 " 0x%02x %u ", wss->hash, wss->secure_status);
154 result += wlp_wss_key_print(buf + result, bufsize - result,
156 result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
158 result += uwb_mac_addr_print(buf + result, bufsize - result,
160 result += scnprintf(buf + result, bufsize - result, " %s", wss->name);
161 result += scnprintf(buf + result, bufsize - result,
162 "\n\n#WSSID\n#WSS broadcast address\n"
163 "#WSS hash\n#WSS secure status\n"
164 "#WSS master key\n#WSS local tag\n"
165 "#WSS local virtual EUI-48\n#WSS name\n");
170 * Show which WSS is activated.
172 ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
176 if (mutex_lock_interruptible(&wss->mutex))
178 if (wss->state >= WLP_WSS_STATE_ACTIVE)
179 result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
181 result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
182 result += scnprintf(buf + result, PAGE_SIZE - result,
184 "# echo WSSID SECURE_STATUS ACCEPT_ENROLLMENT "
185 "NAME #create new WSS\n"
186 "# echo WSSID [DEV ADDR] #enroll in and activate "
187 "existing WSS, can request registrar\n"
189 "# WSSID is a 16 byte hex array. Eg. 12 A3 3B ... \n"
190 "# SECURE_STATUS 0 - unsecure, 1 - secure (default)\n"
191 "# ACCEPT_ENROLLMENT 0 - no, 1 - yes (default)\n"
192 "# NAME is the text string identifying the WSS\n"
193 "# DEV ADDR is the device address of neighbor "
194 "that should be registrar. Eg. 32:AB\n");
196 mutex_unlock(&wss->mutex);
201 EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
204 * Create/activate a new WSS or enroll/activate in neighboring WSS
206 * The user can provide the WSSID of a WSS in which it wants to enroll.
207 * Only the WSSID is necessary if the WSS have been discovered before. If
208 * the WSS has not been discovered before, or the user wants to use a
209 * particular neighbor as its registrar, then the user can also provide a
210 * device address or the neighbor that will be used as registrar.
212 * A new WSS is created when the user provides a WSSID, secure status, and
215 ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
216 const char *buf, size_t size)
218 ssize_t result = -EINVAL;
219 struct wlp_uuid wssid;
220 struct uwb_dev_addr dev;
221 struct uwb_dev_addr bcast = {.data = {0xff, 0xff} };
223 unsigned sec_status, accept;
224 memset(name, 0, sizeof(name));
225 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
226 "%02hhx %02hhx %02hhx %02hhx "
227 "%02hhx %02hhx %02hhx %02hhx "
228 "%02hhx %02hhx %02hhx %02hhx "
230 &wssid.data[0] , &wssid.data[1],
231 &wssid.data[2] , &wssid.data[3],
232 &wssid.data[4] , &wssid.data[5],
233 &wssid.data[6] , &wssid.data[7],
234 &wssid.data[8] , &wssid.data[9],
235 &wssid.data[10], &wssid.data[11],
236 &wssid.data[12], &wssid.data[13],
237 &wssid.data[14], &wssid.data[15],
238 &dev.data[1], &dev.data[0]);
239 if (result == 16 || result == 17) {
240 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
241 "%02hhx %02hhx %02hhx %02hhx "
242 "%02hhx %02hhx %02hhx %02hhx "
243 "%02hhx %02hhx %02hhx %02hhx "
245 &wssid.data[0] , &wssid.data[1],
246 &wssid.data[2] , &wssid.data[3],
247 &wssid.data[4] , &wssid.data[5],
248 &wssid.data[6] , &wssid.data[7],
249 &wssid.data[8] , &wssid.data[9],
250 &wssid.data[10], &wssid.data[11],
251 &wssid.data[12], &wssid.data[13],
252 &wssid.data[14], &wssid.data[15],
253 &sec_status, &accept, name);
255 result = wlp_wss_enroll_activate(wss, &wssid, &bcast);
256 else if (result == 19) {
257 sec_status = sec_status == 0 ? 0 : 1;
258 accept = accept == 0 ? 0 : 1;
259 /* We read name using %c, so the newline needs to be
261 if (strlen(name) != sizeof(name) - 1)
262 name[strlen(name) - 1] = '\0';
263 result = wlp_wss_create_activate(wss, &wssid, name,
267 } else if (result == 18)
268 result = wlp_wss_enroll_activate(wss, &wssid, &dev);
271 return result < 0 ? result : size;
273 EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
276 * Show the UUID of this host
278 ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
282 mutex_lock(&wlp->mutex);
283 result = wlp_wss_uuid_print(buf, PAGE_SIZE, &wlp->uuid);
284 buf[result++] = '\n';
285 mutex_unlock(&wlp->mutex);
288 EXPORT_SYMBOL_GPL(wlp_uuid_show);
291 * Store a new UUID for this host
293 * According to the spec this should be encoded as an octet string in the
294 * order the octets are shown in string representation in RFC 4122 (WLP
297 * We do not check value provided by user.
299 ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
302 struct wlp_uuid uuid;
304 mutex_lock(&wlp->mutex);
305 result = sscanf(buf, "%02hhx %02hhx %02hhx %02hhx "
306 "%02hhx %02hhx %02hhx %02hhx "
307 "%02hhx %02hhx %02hhx %02hhx "
308 "%02hhx %02hhx %02hhx %02hhx ",
309 &uuid.data[0] , &uuid.data[1],
310 &uuid.data[2] , &uuid.data[3],
311 &uuid.data[4] , &uuid.data[5],
312 &uuid.data[6] , &uuid.data[7],
313 &uuid.data[8] , &uuid.data[9],
314 &uuid.data[10], &uuid.data[11],
315 &uuid.data[12], &uuid.data[13],
316 &uuid.data[14], &uuid.data[15]);
323 mutex_unlock(&wlp->mutex);
324 return result < 0 ? result : size;
326 EXPORT_SYMBOL_GPL(wlp_uuid_store);
329 * Show contents of members of device information structure
331 #define wlp_dev_info_show(type) \
332 ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
334 ssize_t result = 0; \
335 mutex_lock(&wlp->mutex); \
336 if (wlp->dev_info == NULL) { \
337 result = __wlp_setup_device_info(wlp); \
341 result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
343 mutex_unlock(&wlp->mutex); \
346 EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
348 wlp_dev_info_show(name)
349 wlp_dev_info_show(model_name)
350 wlp_dev_info_show(model_nr)
351 wlp_dev_info_show(manufacturer)
352 wlp_dev_info_show(serial)
355 * Store contents of members of device information structure
357 #define wlp_dev_info_store(type, len) \
358 ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
362 mutex_lock(&wlp->mutex); \
363 if (wlp->dev_info == NULL) { \
364 result = __wlp_alloc_device_info(wlp); \
368 memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
369 sprintf(format, "%%%uc", len); \
370 result = sscanf(buf, format, wlp->dev_info->type); \
372 mutex_unlock(&wlp->mutex); \
373 return result < 0 ? result : size; \
375 EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
377 wlp_dev_info_store(name, 32)
378 wlp_dev_info_store(manufacturer, 64)
379 wlp_dev_info_store(model_name, 32)
380 wlp_dev_info_store(model_nr, 32)
381 wlp_dev_info_store(serial, 32)
384 const char *__wlp_dev_category[] = {
385 [WLP_DEV_CAT_COMPUTER] = "Computer",
386 [WLP_DEV_CAT_INPUT] = "Input device",
387 [WLP_DEV_CAT_PRINT_SCAN_FAX_COPIER] = "Printer, scanner, FAX, or "
389 [WLP_DEV_CAT_CAMERA] = "Camera",
390 [WLP_DEV_CAT_STORAGE] = "Storage Network",
391 [WLP_DEV_CAT_INFRASTRUCTURE] = "Infrastructure",
392 [WLP_DEV_CAT_DISPLAY] = "Display",
393 [WLP_DEV_CAT_MULTIM] = "Multimedia device",
394 [WLP_DEV_CAT_GAMING] = "Gaming device",
395 [WLP_DEV_CAT_TELEPHONE] = "Telephone",
396 [WLP_DEV_CAT_OTHER] = "Other",
400 const char *wlp_dev_category_str(unsigned cat)
402 if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
403 || cat == WLP_DEV_CAT_OTHER)
404 return __wlp_dev_category[cat];
405 return "unknown category";
408 ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
411 mutex_lock(&wlp->mutex);
412 if (wlp->dev_info == NULL) {
413 result = __wlp_setup_device_info(wlp);
417 result = scnprintf(buf, PAGE_SIZE, "%s\n",
418 wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
420 mutex_unlock(&wlp->mutex);
423 EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
425 ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
430 mutex_lock(&wlp->mutex);
431 if (wlp->dev_info == NULL) {
432 result = __wlp_alloc_device_info(wlp);
436 result = sscanf(buf, "%hu", &cat);
437 if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
438 || cat == WLP_DEV_CAT_OTHER)
439 wlp->dev_info->prim_dev_type.category = cat;
443 mutex_unlock(&wlp->mutex);
444 return result < 0 ? result : size;
446 EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
448 ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
451 mutex_lock(&wlp->mutex);
452 if (wlp->dev_info == NULL) {
453 result = __wlp_setup_device_info(wlp);
457 result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
458 wlp->dev_info->prim_dev_type.OUI[0],
459 wlp->dev_info->prim_dev_type.OUI[1],
460 wlp->dev_info->prim_dev_type.OUI[2]);
462 mutex_unlock(&wlp->mutex);
465 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
467 ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
471 mutex_lock(&wlp->mutex);
472 if (wlp->dev_info == NULL) {
473 result = __wlp_alloc_device_info(wlp);
477 result = sscanf(buf, "%hhx:%hhx:%hhx",
478 &OUI[0], &OUI[1], &OUI[2]);
483 memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
485 mutex_unlock(&wlp->mutex);
486 return result < 0 ? result : size;
488 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
491 ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
494 mutex_lock(&wlp->mutex);
495 if (wlp->dev_info == NULL) {
496 result = __wlp_setup_device_info(wlp);
500 result = scnprintf(buf, PAGE_SIZE, "%u\n",
501 wlp->dev_info->prim_dev_type.OUIsubdiv);
503 mutex_unlock(&wlp->mutex);
506 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
508 ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
514 mutex_lock(&wlp->mutex);
515 if (wlp->dev_info == NULL) {
516 result = __wlp_alloc_device_info(wlp);
520 result = sscanf(buf, "%u", &sub);
522 wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
526 mutex_unlock(&wlp->mutex);
527 return result < 0 ? result : size;
529 EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
531 ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
534 mutex_lock(&wlp->mutex);
535 if (wlp->dev_info == NULL) {
536 result = __wlp_setup_device_info(wlp);
540 result = scnprintf(buf, PAGE_SIZE, "%u\n",
541 wlp->dev_info->prim_dev_type.subID);
543 mutex_unlock(&wlp->mutex);
546 EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
548 ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
554 mutex_lock(&wlp->mutex);
555 if (wlp->dev_info == NULL) {
556 result = __wlp_alloc_device_info(wlp);
560 result = sscanf(buf, "%u", &sub);
562 wlp->dev_info->prim_dev_type.subID = sub;
566 mutex_unlock(&wlp->mutex);
567 return result < 0 ? result : size;
569 EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
572 * Subsystem implementation for interaction with individual WSS via sysfs
574 * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
577 #define kobj_to_wlp_wss(obj) container_of(obj, struct wlp_wss, kobj)
578 #define attr_to_wlp_wss_attr(_attr) \
579 container_of(_attr, struct wlp_wss_attribute, attr)
582 * Sysfs subsystem: forward read calls
584 * Sysfs operation for forwarding read call to the show method of the
588 ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
591 struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
592 struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
596 ret = wss_attr->show(wss, buf);
600 * Sysfs subsystem: forward write calls
602 * Sysfs operation for forwarding write call to the store method of the
606 ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
607 const char *buf, size_t count)
609 struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
610 struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
614 ret = wss_attr->store(wss, buf, count);
619 struct sysfs_ops wss_sysfs_ops = {
620 .show = wlp_wss_attr_show,
621 .store = wlp_wss_attr_store,
624 struct kobj_type wss_ktype = {
625 .release = wlp_wss_release,
626 .sysfs_ops = &wss_sysfs_ops,
631 * Sysfs files for individual WSS
635 * Print static properties of this WSS
637 * The name of a WSS may not be null teminated. It's max size is 64 bytes
638 * so we copy it to a larger array just to make sure we print sane data.
640 static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
644 if (mutex_lock_interruptible(&wss->mutex))
646 result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
647 mutex_unlock(&wss->mutex);
651 WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
654 * Print all connected members of this WSS
655 * The EDA cache contains all members of WSS neighborhood.
657 static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
659 struct wlp *wlp = container_of(wss, struct wlp, wss);
660 return wlp_eda_show(wlp, buf);
662 WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
665 const char *__wlp_strstate[] = {
667 "partially enrolled",
673 static const char *wlp_wss_strstate(unsigned state)
675 if (state >= ARRAY_SIZE(__wlp_strstate))
676 return "unknown state";
677 return __wlp_strstate[state];
681 * Print current state of this WSS
683 static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
687 if (mutex_lock_interruptible(&wss->mutex))
689 result = scnprintf(buf, PAGE_SIZE, "%s\n",
690 wlp_wss_strstate(wss->state));
691 mutex_unlock(&wss->mutex);
695 WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
699 struct attribute *wss_attrs[] = {
700 &wss_attr_properties.attr,
701 &wss_attr_members.attr,
702 &wss_attr_state.attr,
706 struct attribute_group wss_attr_group = {
707 .name = NULL, /* we want them in the same directory */