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
26 #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
);
618 static const struct sysfs_ops wss_sysfs_ops
= {
619 .show
= wlp_wss_attr_show
,
620 .store
= wlp_wss_attr_store
,
623 struct kobj_type wss_ktype
= {
624 .release
= wlp_wss_release
,
625 .sysfs_ops
= &wss_sysfs_ops
,
630 * Sysfs files for individual WSS
634 * Print static properties of this WSS
636 * The name of a WSS may not be null teminated. It's max size is 64 bytes
637 * so we copy it to a larger array just to make sure we print sane data.
639 static ssize_t
wlp_wss_properties_show(struct wlp_wss
*wss
, char *buf
)
643 if (mutex_lock_interruptible(&wss
->mutex
))
645 result
= __wlp_wss_properties_show(wss
, buf
, PAGE_SIZE
);
646 mutex_unlock(&wss
->mutex
);
650 WSS_ATTR(properties
, S_IRUGO
, wlp_wss_properties_show
, NULL
);
653 * Print all connected members of this WSS
654 * The EDA cache contains all members of WSS neighborhood.
656 static ssize_t
wlp_wss_members_show(struct wlp_wss
*wss
, char *buf
)
658 struct wlp
*wlp
= container_of(wss
, struct wlp
, wss
);
659 return wlp_eda_show(wlp
, buf
);
661 WSS_ATTR(members
, S_IRUGO
, wlp_wss_members_show
, NULL
);
664 const char *__wlp_strstate
[] = {
666 "partially enrolled",
672 static const char *wlp_wss_strstate(unsigned state
)
674 if (state
>= ARRAY_SIZE(__wlp_strstate
))
675 return "unknown state";
676 return __wlp_strstate
[state
];
680 * Print current state of this WSS
682 static ssize_t
wlp_wss_state_show(struct wlp_wss
*wss
, char *buf
)
686 if (mutex_lock_interruptible(&wss
->mutex
))
688 result
= scnprintf(buf
, PAGE_SIZE
, "%s\n",
689 wlp_wss_strstate(wss
->state
));
690 mutex_unlock(&wss
->mutex
);
694 WSS_ATTR(state
, S_IRUGO
, wlp_wss_state_show
, NULL
);
698 struct attribute
*wss_attrs
[] = {
699 &wss_attr_properties
.attr
,
700 &wss_attr_members
.attr
,
701 &wss_attr_state
.attr
,
705 struct attribute_group wss_attr_group
= {
706 .name
= NULL
, /* we want them in the same directory */