Showing error 1856

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/uwb/wlp/sysfs.c
Line in file: 418
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

  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
 27#include <linux/wlp.h>
 28#include "wlp-internal.h"
 29
 30static
 31size_t wlp_wss_wssid_e_print(char *buf, size_t bufsize,
 32                             struct wlp_wssid_e *wssid_e)
 33{
 34        size_t used = 0;
 35        used += scnprintf(buf, bufsize, " WSS: ");
 36        used += wlp_wss_uuid_print(buf + used, bufsize - used,
 37                                   &wssid_e->wssid);
 38
 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,
 46                                  wssid_e->info->name);
 47        }
 48        return used;
 49}
 50
 51/**
 52 * Print out information learned from neighbor discovery
 53 *
 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
 57 * being referenced.
 58 * The information being printed is for one time use - temporary storage is
 59 * cleaned after it is printed.
 60 *
 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
 64 * separator.
 65 */
 66static
 67ssize_t wlp_wss_neighborhood_print_remove(struct wlp *wlp, char *buf,
 68                                   size_t bufsize)
 69{
 70        size_t used = 0;
 71        struct wlp_neighbor_e *neighb;
 72        struct wlp_wssid_e *wssid_e;
 73
 74        mutex_lock(&wlp->nbmutex);
 75        used = scnprintf(buf, bufsize, "#Neighbor information\n"
 76                         "#uuid dev_addr\n"
 77                         "# Device Name:\n# Model Name:\n# Manufacturer:\n"
 78                         "# Model Nr:\n# Serial:\n"
 79                         "# Pri Dev type: CategoryID OUI OUISubdiv "
 80                         "SubcategoryID\n"
 81                         "# WSS: WSSID WSS_name accept_enroll sec_status "
 82                         "bcast\n"
 83                         "# WSS: WSSID WSS_name accept_enroll sec_status "
 84                         "bcast\n\n");
 85        list_for_each_entry(neighb, &wlp->neighbors, node) {
 86                if (bufsize - used <= 0)
 87                        goto out;
 88                used += wlp_wss_uuid_print(buf + used, bufsize - used,
 89                                           &neighb->uuid);
 90                buf[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"
 96                                          " Model Name: %s\n"
 97                                          " Manufacturer:%s \n"
 98                                          " Model Nr: %s\n"
 99                                          " Serial: %s\n"
100                                          " Pri Dev type: "
101                                          "%u %02x:%02x:%02x %u %u\n",
102                                          neighb->info->name,
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,
115                                                      bufsize - used,
116                                                      wssid_e);
117                }
118                buf[used++] = '\n';
119                wlp_remove_neighbor_tmp_info(neighb);
120        }
121
122
123out:
124        mutex_unlock(&wlp->nbmutex);
125        return used;
126}
127
128
129/**
130 * Show properties of all WSS in neighborhood.
131 *
132 * Will trigger a complete discovery of WSS activated by this device and
133 * its neighbors.
134 */
135ssize_t wlp_neighborhood_show(struct wlp *wlp, char *buf)
136{
137        wlp_discover(wlp);
138        return wlp_wss_neighborhood_print_remove(wlp, buf, PAGE_SIZE);
139}
140EXPORT_SYMBOL_GPL(wlp_neighborhood_show);
141
142static
143ssize_t __wlp_wss_properties_show(struct wlp_wss *wss, char *buf,
144                                  size_t bufsize)
145{
146        ssize_t result;
147
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,
151                                     &wss->bcast);
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,
155                                    wss->master_key);
156        result += scnprintf(buf + result, bufsize - result, " 0x%02x ",
157                            wss->tag);
158        result += uwb_mac_addr_print(buf + result, bufsize - result,
159                                     &wss->virtual_addr);
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");
166        return result;
167}
168
169/**
170 * Show which WSS is activated.
171 */
172ssize_t wlp_wss_activate_show(struct wlp_wss *wss, char *buf)
173{
174        int result = 0;
175
176        if (mutex_lock_interruptible(&wss->mutex))
177                goto out;
178        if (wss->state >= WLP_WSS_STATE_ACTIVE)
179                result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
180        else
181                result = scnprintf(buf, PAGE_SIZE, "No local WSS active.\n");
182        result += scnprintf(buf + result, PAGE_SIZE - result,
183                        "\n\n"
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"
188                        "#\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");
195
196        mutex_unlock(&wss->mutex);
197out:
198        return result;
199
200}
201EXPORT_SYMBOL_GPL(wlp_wss_activate_show);
202
203/**
204 * Create/activate a new WSS or enroll/activate in neighboring WSS
205 *
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.
211 *
212 * A new WSS is created when the user provides a WSSID, secure status, and
213 * WSS name.
214 */
215ssize_t wlp_wss_activate_store(struct wlp_wss *wss,
216                               const char *buf, size_t size)
217{
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} };
222        char name[65];
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 "
229                        "%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 "
244                                "%u %u %64c",
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);
254                if (result == 16)
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
260                         * removed */
261                        if (strlen(name) != sizeof(name) - 1)
262                                name[strlen(name) - 1] = '\0';
263                        result = wlp_wss_create_activate(wss, &wssid, name,
264                                                         sec_status, accept);
265                } else
266                        result = -EINVAL;
267        } else if (result == 18)
268                result = wlp_wss_enroll_activate(wss, &wssid, &dev);
269        else
270                result = -EINVAL;
271        return result < 0 ? result : size;
272}
273EXPORT_SYMBOL_GPL(wlp_wss_activate_store);
274
275/**
276 * Show the UUID of this host
277 */
278ssize_t wlp_uuid_show(struct wlp *wlp, char *buf)
279{
280        ssize_t result = 0;
281
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);
286        return result;
287}
288EXPORT_SYMBOL_GPL(wlp_uuid_show);
289
290/**
291 * Store a new UUID for this host
292 *
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
295 * 0.99 [Table 6])
296 *
297 * We do not check value provided by user.
298 */
299ssize_t wlp_uuid_store(struct wlp *wlp, const char *buf, size_t size)
300{
301        ssize_t result;
302        struct wlp_uuid uuid;
303
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]);
317        if (result != 16) {
318                result = -EINVAL;
319                goto error;
320        }
321        wlp->uuid = uuid;
322error:
323        mutex_unlock(&wlp->mutex);
324        return result < 0 ? result : size;
325}
326EXPORT_SYMBOL_GPL(wlp_uuid_store);
327
328/**
329 * Show contents of members of device information structure
330 */
331#define wlp_dev_info_show(type)                                                \
332ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf)                \
333{                                                                        \
334        ssize_t result = 0;                                                \
335        mutex_lock(&wlp->mutex);                                        \
336        if (wlp->dev_info == NULL) {                                        \
337                result = __wlp_setup_device_info(wlp);                        \
338                if (result < 0)                                                \
339                        goto out;                                        \
340        }                                                                \
341        result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
342out:                                                                        \
343        mutex_unlock(&wlp->mutex);                                        \
344        return result;                                                        \
345}                                                                        \
346EXPORT_SYMBOL_GPL(wlp_dev_##type##_show);
347
348wlp_dev_info_show(name)
349wlp_dev_info_show(model_name)
350wlp_dev_info_show(model_nr)
351wlp_dev_info_show(manufacturer)
352wlp_dev_info_show(serial)
353
354/**
355 * Store contents of members of device information structure
356 */
357#define wlp_dev_info_store(type, len)                                        \
358ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
359{                                                                        \
360        ssize_t result;                                                        \
361        char format[10];                                                \
362        mutex_lock(&wlp->mutex);                                        \
363        if (wlp->dev_info == NULL) {                                        \
364                result = __wlp_alloc_device_info(wlp);                        \
365                if (result < 0)                                                \
366                        goto out;                                        \
367        }                                                                \
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);                \
371out:                                                                        \
372        mutex_unlock(&wlp->mutex);                                        \
373        return result < 0 ? result : size;                                \
374}                                                                        \
375EXPORT_SYMBOL_GPL(wlp_dev_##type##_store);
376
377wlp_dev_info_store(name, 32)
378wlp_dev_info_store(manufacturer, 64)
379wlp_dev_info_store(model_name, 32)
380wlp_dev_info_store(model_nr, 32)
381wlp_dev_info_store(serial, 32)
382
383static
384const 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 "
388                                              "Copier",
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",
397};
398
399static
400const char *wlp_dev_category_str(unsigned cat)
401{
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";
406}
407
408ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
409{
410        ssize_t result = 0;
411        mutex_lock(&wlp->mutex);
412        if (wlp->dev_info == NULL) {
413                result = __wlp_setup_device_info(wlp);
414                if (result < 0)
415                        goto out;
416        }
417        result = scnprintf(buf, PAGE_SIZE, "%s\n",
418                  wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
419out:
420        mutex_unlock(&wlp->mutex);
421        return result;
422}
423EXPORT_SYMBOL_GPL(wlp_dev_prim_category_show);
424
425ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
426                                    size_t size)
427{
428        ssize_t result;
429        u16 cat;
430        mutex_lock(&wlp->mutex);
431        if (wlp->dev_info == NULL) {
432                result = __wlp_alloc_device_info(wlp);
433                if (result < 0)
434                        goto out;
435        }
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;
440        else
441                result = -EINVAL;
442out:
443        mutex_unlock(&wlp->mutex);
444        return result < 0 ? result : size;
445}
446EXPORT_SYMBOL_GPL(wlp_dev_prim_category_store);
447
448ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
449{
450        ssize_t result = 0;
451        mutex_lock(&wlp->mutex);
452        if (wlp->dev_info == NULL) {
453                result = __wlp_setup_device_info(wlp);
454                if (result < 0)
455                        goto out;
456        }
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]);
461out:
462        mutex_unlock(&wlp->mutex);
463        return result;
464}
465EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_show);
466
467ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
468{
469        ssize_t result;
470        u8 OUI[3];
471        mutex_lock(&wlp->mutex);
472        if (wlp->dev_info == NULL) {
473                result = __wlp_alloc_device_info(wlp);
474                if (result < 0)
475                        goto out;
476        }
477        result = sscanf(buf, "%hhx:%hhx:%hhx",
478                        &OUI[0], &OUI[1], &OUI[2]);
479        if (result != 3) {
480                result = -EINVAL;
481                goto out;
482        } else
483                memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
484out:
485        mutex_unlock(&wlp->mutex);
486        return result < 0 ? result : size;
487}
488EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_store);
489
490
491ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
492{
493        ssize_t result = 0;
494        mutex_lock(&wlp->mutex);
495        if (wlp->dev_info == NULL) {
496                result = __wlp_setup_device_info(wlp);
497                if (result < 0)
498                        goto out;
499        }
500        result = scnprintf(buf, PAGE_SIZE, "%u\n",
501                           wlp->dev_info->prim_dev_type.OUIsubdiv);
502out:
503        mutex_unlock(&wlp->mutex);
504        return result;
505}
506EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_show);
507
508ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
509                                   size_t size)
510{
511        ssize_t result;
512        unsigned sub;
513        u8 max_sub = ~0;
514        mutex_lock(&wlp->mutex);
515        if (wlp->dev_info == NULL) {
516                result = __wlp_alloc_device_info(wlp);
517                if (result < 0)
518                        goto out;
519        }
520        result = sscanf(buf, "%u", &sub);
521        if (sub <= max_sub)
522                wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
523        else
524                result = -EINVAL;
525out:
526        mutex_unlock(&wlp->mutex);
527        return result < 0 ? result : size;
528}
529EXPORT_SYMBOL_GPL(wlp_dev_prim_OUI_sub_store);
530
531ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
532{
533        ssize_t result = 0;
534        mutex_lock(&wlp->mutex);
535        if (wlp->dev_info == NULL) {
536                result = __wlp_setup_device_info(wlp);
537                if (result < 0)
538                        goto out;
539        }
540        result = scnprintf(buf, PAGE_SIZE, "%u\n",
541                           wlp->dev_info->prim_dev_type.subID);
542out:
543        mutex_unlock(&wlp->mutex);
544        return result;
545}
546EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_show);
547
548ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
549                                  size_t size)
550{
551        ssize_t result;
552        unsigned sub;
553        __le16 max_sub = ~0;
554        mutex_lock(&wlp->mutex);
555        if (wlp->dev_info == NULL) {
556                result = __wlp_alloc_device_info(wlp);
557                if (result < 0)
558                        goto out;
559        }
560        result = sscanf(buf, "%u", &sub);
561        if (sub <= max_sub)
562                wlp->dev_info->prim_dev_type.subID = sub;
563        else
564                result = -EINVAL;
565out:
566        mutex_unlock(&wlp->mutex);
567        return result < 0 ? result : size;
568}
569EXPORT_SYMBOL_GPL(wlp_dev_prim_subcat_store);
570
571/**
572 * Subsystem implementation for interaction with individual WSS via sysfs
573 *
574 * Followed instructions for subsystem in Documentation/filesystems/sysfs.txt
575 */
576
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)
580
581/**
582 * Sysfs subsystem: forward read calls
583 *
584 * Sysfs operation for forwarding read call to the show method of the
585 * attribute owner
586 */
587static
588ssize_t wlp_wss_attr_show(struct kobject *kobj, struct attribute *attr,
589                          char *buf)
590{
591        struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
592        struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
593        ssize_t ret = -EIO;
594
595        if (wss_attr->show)
596                ret = wss_attr->show(wss, buf);
597        return ret;
598}
599/**
600 * Sysfs subsystem: forward write calls
601 *
602 * Sysfs operation for forwarding write call to the store method of the
603 * attribute owner
604 */
605static
606ssize_t wlp_wss_attr_store(struct kobject *kobj, struct attribute *attr,
607                           const char *buf, size_t count)
608{
609        struct wlp_wss_attribute *wss_attr = attr_to_wlp_wss_attr(attr);
610        struct wlp_wss *wss = kobj_to_wlp_wss(kobj);
611        ssize_t ret = -EIO;
612
613        if (wss_attr->store)
614                ret = wss_attr->store(wss, buf, count);
615        return ret;
616}
617
618static
619struct sysfs_ops wss_sysfs_ops = {
620        .show        = wlp_wss_attr_show,
621        .store        = wlp_wss_attr_store,
622};
623
624struct kobj_type wss_ktype = {
625        .release        = wlp_wss_release,
626        .sysfs_ops        = &wss_sysfs_ops,
627};
628
629
630/**
631 * Sysfs files for individual WSS
632 */
633
634/**
635 * Print static properties of this WSS
636 *
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.
639 */
640static ssize_t wlp_wss_properties_show(struct wlp_wss *wss, char *buf)
641{
642        int result = 0;
643
644        if (mutex_lock_interruptible(&wss->mutex))
645                goto out;
646        result = __wlp_wss_properties_show(wss, buf, PAGE_SIZE);
647        mutex_unlock(&wss->mutex);
648out:
649        return result;
650}
651WSS_ATTR(properties, S_IRUGO, wlp_wss_properties_show, NULL);
652
653/**
654 * Print all connected members of this WSS
655 * The EDA cache contains all members of WSS neighborhood.
656 */
657static ssize_t wlp_wss_members_show(struct wlp_wss *wss, char *buf)
658{
659        struct wlp *wlp = container_of(wss, struct wlp, wss);
660        return wlp_eda_show(wlp, buf);
661}
662WSS_ATTR(members, S_IRUGO, wlp_wss_members_show, NULL);
663
664static
665const char *__wlp_strstate[] = {
666        "none",
667        "partially enrolled",
668        "enrolled",
669        "active",
670        "connected",
671};
672
673static const char *wlp_wss_strstate(unsigned state)
674{
675        if (state >= ARRAY_SIZE(__wlp_strstate))
676                return "unknown state";
677        return __wlp_strstate[state];
678}
679
680/*
681 * Print current state of this WSS
682 */
683static ssize_t wlp_wss_state_show(struct wlp_wss *wss, char *buf)
684{
685        int result = 0;
686
687        if (mutex_lock_interruptible(&wss->mutex))
688                goto out;
689        result = scnprintf(buf, PAGE_SIZE, "%s\n",
690                           wlp_wss_strstate(wss->state));
691        mutex_unlock(&wss->mutex);
692out:
693        return result;
694}
695WSS_ATTR(state, S_IRUGO, wlp_wss_state_show, NULL);
696
697
698static
699struct attribute *wss_attrs[] = {
700        &wss_attr_properties.attr,
701        &wss_attr_members.attr,
702        &wss_attr_state.attr,
703        NULL,
704};
705
706struct attribute_group wss_attr_group = {
707        .name = NULL,        /* we want them in the same directory */
708        .attrs = wss_attrs,
709};