1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/wlp.h>
27#define D_LOCAL 6
28#include <linux/uwb/debug.h>
29#include "wlp-internal.h"
30
31static
32const char *__wlp_assoc_frame[] = {
33 [WLP_ASSOC_D1] = "WLP_ASSOC_D1",
34 [WLP_ASSOC_D2] = "WLP_ASSOC_D2",
35 [WLP_ASSOC_M1] = "WLP_ASSOC_M1",
36 [WLP_ASSOC_M2] = "WLP_ASSOC_M2",
37 [WLP_ASSOC_M3] = "WLP_ASSOC_M3",
38 [WLP_ASSOC_M4] = "WLP_ASSOC_M4",
39 [WLP_ASSOC_M5] = "WLP_ASSOC_M5",
40 [WLP_ASSOC_M6] = "WLP_ASSOC_M6",
41 [WLP_ASSOC_M7] = "WLP_ASSOC_M7",
42 [WLP_ASSOC_M8] = "WLP_ASSOC_M8",
43 [WLP_ASSOC_F0] = "WLP_ASSOC_F0",
44 [WLP_ASSOC_E1] = "WLP_ASSOC_E1",
45 [WLP_ASSOC_E2] = "WLP_ASSOC_E2",
46 [WLP_ASSOC_C1] = "WLP_ASSOC_C1",
47 [WLP_ASSOC_C2] = "WLP_ASSOC_C2",
48 [WLP_ASSOC_C3] = "WLP_ASSOC_C3",
49 [WLP_ASSOC_C4] = "WLP_ASSOC_C4",
50};
51
52static const char *wlp_assoc_frame_str(unsigned id)
53{
54 if (id >= ARRAY_SIZE(__wlp_assoc_frame))
55 return "unknown association frame";
56 return __wlp_assoc_frame[id];
57}
58
59static const char *__wlp_assc_error[] = {
60 "none",
61 "Authenticator Failure",
62 "Rogue activity suspected",
63 "Device busy",
64 "Setup Locked",
65 "Registrar not ready",
66 "Invalid WSS selection",
67 "Message timeout",
68 "Enrollment session timeout",
69 "Device password invalid",
70 "Unsupported version",
71 "Internal error",
72 "Undefined error",
73 "Numeric comparison failure",
74 "Waiting for user input",
75};
76
77static const char *wlp_assc_error_str(unsigned id)
78{
79 if (id >= ARRAY_SIZE(__wlp_assc_error))
80 return "unknown WLP association error";
81 return __wlp_assc_error[id];
82}
83
84static inline void wlp_set_attr_hdr(struct wlp_attr_hdr *hdr, unsigned type,
85 size_t len)
86{
87 hdr->type = cpu_to_le16(type);
88 hdr->length = cpu_to_le16(len);
89}
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105#define wlp_set(type, type_code, name) \
106static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
107{ \
108 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
109 wlp_set_attr_hdr(&attr->hdr, type_code, \
110 sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
111 attr->name = value; \
112 d_dump(6, NULL, attr, sizeof(*attr)); \
113 d_fnend(6, NULL, "(attribute %p)\n", attr); \
114 return sizeof(*attr); \
115}
116
117#define wlp_pset(type, type_code, name) \
118static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value) \
119{ \
120 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
121 wlp_set_attr_hdr(&attr->hdr, type_code, \
122 sizeof(*attr) - sizeof(struct wlp_attr_hdr)); \
123 attr->name = *value; \
124 d_dump(6, NULL, attr, sizeof(*attr)); \
125 d_fnend(6, NULL, "(attribute %p)\n", attr); \
126 return sizeof(*attr); \
127}
128
129
130
131
132
133
134
135
136
137
138#define wlp_vset(type, type_code, name) \
139static size_t wlp_set_##name(struct wlp_attr_##name *attr, type value, \
140 size_t len) \
141{ \
142 d_fnstart(6, NULL, "(attribute %p)\n", attr); \
143 wlp_set_attr_hdr(&attr->hdr, type_code, len); \
144 memcpy(attr->name, value, len); \
145 d_dump(6, NULL, attr, sizeof(*attr) + len); \
146 d_fnend(6, NULL, "(attribute %p)\n", attr); \
147 return sizeof(*attr) + len; \
148}
149
150wlp_vset(char *, WLP_ATTR_DEV_NAME, dev_name)
151wlp_vset(char *, WLP_ATTR_MANUF, manufacturer)
152wlp_set(enum wlp_assoc_type, WLP_ATTR_MSG_TYPE, msg_type)
153wlp_vset(char *, WLP_ATTR_MODEL_NAME, model_name)
154wlp_vset(char *, WLP_ATTR_MODEL_NR, model_nr)
155wlp_vset(char *, WLP_ATTR_SERIAL, serial)
156wlp_vset(char *, WLP_ATTR_WSS_NAME, wss_name)
157wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_E, uuid_e)
158wlp_pset(struct wlp_uuid *, WLP_ATTR_UUID_R, uuid_r)
159wlp_pset(struct wlp_uuid *, WLP_ATTR_WSSID, wssid)
160wlp_pset(struct wlp_dev_type *, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
161
162wlp_set(u8, WLP_ATTR_WLP_VER, version)
163wlp_set(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
164wlp_set(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
165wlp_set(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
166wlp_set(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
167wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_BCAST, wss_bcast)
168wlp_pset(struct wlp_nonce *, WLP_ATTR_ENRL_NONCE, enonce)
169wlp_pset(struct wlp_nonce *, WLP_ATTR_REG_NONCE, rnonce)
170wlp_set(u8, WLP_ATTR_WSS_TAG, wss_tag)
171wlp_pset(struct uwb_mac_addr *, WLP_ATTR_WSS_VIRT, wss_virt)
172
173
174
175
176
177
178
179static size_t wlp_set_wss_info(struct wlp_attr_wss_info *attr,
180 struct wlp_wss *wss)
181{
182 size_t datalen;
183 void *ptr = attr->wss_info;
184 size_t used = sizeof(*attr);
185 d_fnstart(6, NULL, "(attribute %p)\n", attr);
186 datalen = sizeof(struct wlp_wss_info) + strlen(wss->name);
187 wlp_set_attr_hdr(&attr->hdr, WLP_ATTR_WSS_INFO, datalen);
188 used = wlp_set_wssid(ptr, &wss->wssid);
189 used += wlp_set_wss_name(ptr + used, wss->name, strlen(wss->name));
190 used += wlp_set_accept_enrl(ptr + used, wss->accept_enroll);
191 used += wlp_set_wss_sec_status(ptr + used, wss->secure_status);
192 used += wlp_set_wss_bcast(ptr + used, &wss->bcast);
193 d_dump(6, NULL, attr, sizeof(*attr) + datalen);
194 d_fnend(6, NULL, "(attribute %p, used %d)\n",
195 attr, (int)(sizeof(*attr) + used));
196 return sizeof(*attr) + used;
197}
198
199
200
201
202
203
204
205
206
207
208
209
210static int wlp_check_attr_hdr(struct wlp *wlp, struct wlp_attr_hdr *hdr,
211 enum wlp_attr_type type, unsigned len)
212{
213 struct device *dev = &wlp->rc->uwb_dev.dev;
214
215 if (le16_to_cpu(hdr->type) != type) {
216 dev_err(dev, "WLP: unexpected header type. Expected "
217 "%u, got %u.\n", type, le16_to_cpu(hdr->type));
218 return -EINVAL;
219 }
220 if (le16_to_cpu(hdr->length) != len) {
221 dev_err(dev, "WLP: unexpected length in header. Expected "
222 "%u, got %u.\n", len, le16_to_cpu(hdr->length));
223 return -EINVAL;
224 }
225 return 0;
226}
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243static int wlp_check_wss_info_attr_hdr(struct wlp *wlp,
244 struct wlp_attr_hdr *hdr, size_t buflen)
245{
246 struct device *dev = &wlp->rc->uwb_dev.dev;
247 size_t len;
248 int result = 0;
249
250 if (buflen < sizeof(*hdr)) {
251 dev_err(dev, "WLP: Not enough space in buffer to parse"
252 " WSS information attribute header.\n");
253 result = -EIO;
254 goto out;
255 }
256 if (le16_to_cpu(hdr->type) != WLP_ATTR_WSS_INFO) {
257
258 result = -ENODATA;
259 goto out;
260 }
261 len = le16_to_cpu(hdr->length);
262 if (buflen < sizeof(*hdr) + len) {
263 dev_err(dev, "WLP: Not enough space in buffer to parse "
264 "variable data. Got %d, expected %d.\n",
265 (int)buflen, (int)(sizeof(*hdr) + len));
266 result = -EIO;
267 goto out;
268 }
269 result = len;
270out:
271 return result;
272}
273
274
275
276
277
278
279
280
281
282
283
284
285
286#define wlp_get(type, type_code, name) \
287ssize_t wlp_get_##name(struct wlp *wlp, struct wlp_attr_##name *attr, \
288 type *value, ssize_t buflen) \
289{ \
290 struct device *dev = &wlp->rc->uwb_dev.dev; \
291 if (buflen < 0) \
292 return -EINVAL; \
293 if (buflen < sizeof(*attr)) { \
294 dev_err(dev, "WLP: Not enough space in buffer to parse" \
295 " attribute field. Need %d, received %zu\n", \
296 (int)sizeof(*attr), buflen); \
297 return -EIO; \
298 } \
299 if (wlp_check_attr_hdr(wlp, &attr->hdr, type_code, \
300 sizeof(attr->name)) < 0) { \
301 dev_err(dev, "WLP: Header verification failed. \n"); \
302 return -EINVAL; \
303 } \
304 *value = attr->name; \
305 return sizeof(*attr); \
306}
307
308#define wlp_get_sparse(type, type_code, name) \
309 static wlp_get(type, type_code, name)
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324#define wlp_vget(type_val, type_code, name, max) \
325static ssize_t wlp_get_##name(struct wlp *wlp, \
326 struct wlp_attr_##name *attr, \
327 type_val *value, ssize_t buflen) \
328{ \
329 struct device *dev = &wlp->rc->uwb_dev.dev; \
330 size_t len; \
331 if (buflen < 0) \
332 return -EINVAL; \
333 if (buflen < sizeof(*attr)) { \
334 dev_err(dev, "WLP: Not enough space in buffer to parse" \
335 " header.\n"); \
336 return -EIO; \
337 } \
338 if (le16_to_cpu(attr->hdr.type) != type_code) { \
339 dev_err(dev, "WLP: Unexpected attribute type. Got %u, " \
340 "expected %u.\n", le16_to_cpu(attr->hdr.type), \
341 type_code); \
342 return -EINVAL; \
343 } \
344 len = le16_to_cpu(attr->hdr.length); \
345 if (len > max) { \
346 dev_err(dev, "WLP: Attribute larger than maximum " \
347 "allowed. Received %zu, max is %d.\n", len, \
348 (int)max); \
349 return -EFBIG; \
350 } \
351 if (buflen < sizeof(*attr) + len) { \
352 dev_err(dev, "WLP: Not enough space in buffer to parse "\
353 "variable data.\n"); \
354 return -EIO; \
355 } \
356 memcpy(value, (void *) attr + sizeof(*attr), len); \
357 return sizeof(*attr) + len; \
358}
359
360wlp_get(u8, WLP_ATTR_WLP_VER, version)
361wlp_get_sparse(enum wlp_wss_sel_mthd, WLP_ATTR_WSS_SEL_MTHD, wss_sel_mthd)
362wlp_get_sparse(struct wlp_dev_type, WLP_ATTR_PRI_DEV_TYPE, prim_dev_type)
363wlp_get_sparse(enum wlp_assc_error, WLP_ATTR_WLP_ASSC_ERR, wlp_assc_err)
364wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_E, uuid_e)
365wlp_get_sparse(struct wlp_uuid, WLP_ATTR_UUID_R, uuid_r)
366wlp_get(struct wlp_uuid, WLP_ATTR_WSSID, wssid)
367wlp_get_sparse(u8, WLP_ATTR_ACC_ENRL, accept_enrl)
368wlp_get_sparse(u8, WLP_ATTR_WSS_SEC_STAT, wss_sec_status)
369wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_BCAST, wss_bcast)
370wlp_get_sparse(u8, WLP_ATTR_WSS_TAG, wss_tag)
371wlp_get_sparse(struct uwb_mac_addr, WLP_ATTR_WSS_VIRT, wss_virt)
372wlp_get_sparse(struct wlp_nonce, WLP_ATTR_ENRL_NONCE, enonce)
373wlp_get_sparse(struct wlp_nonce, WLP_ATTR_REG_NONCE, rnonce)
374
375
376
377
378
379
380
381
382
383wlp_vget(char, WLP_ATTR_WSS_NAME, wss_name,
384 FIELD_SIZEOF(struct wlp_wss, name) - 1)
385wlp_vget(char, WLP_ATTR_DEV_NAME, dev_name,
386 FIELD_SIZEOF(struct wlp_device_info, name) - 1)
387wlp_vget(char, WLP_ATTR_MANUF, manufacturer,
388 FIELD_SIZEOF(struct wlp_device_info, manufacturer) - 1)
389wlp_vget(char, WLP_ATTR_MODEL_NAME, model_name,
390 FIELD_SIZEOF(struct wlp_device_info, model_name) - 1)
391wlp_vget(char, WLP_ATTR_MODEL_NR, model_nr,
392 FIELD_SIZEOF(struct wlp_device_info, model_nr) - 1)
393wlp_vget(char, WLP_ATTR_SERIAL, serial,
394 FIELD_SIZEOF(struct wlp_device_info, serial) - 1)
395
396
397
398
399
400
401
402
403
404
405
406
407static ssize_t wlp_get_wss_info_attrs(struct wlp *wlp,
408 struct wlp_attr_hdr *attr,
409 struct wlp_wss_tmp_info *info,
410 ssize_t buflen)
411{
412 struct device *dev = &wlp->rc->uwb_dev.dev;
413 void *ptr = attr;
414 size_t used = 0;
415 ssize_t result = -EINVAL;
416
417 d_printf(6, dev, "WLP: WSS info: Retrieving WSS name\n");
418 result = wlp_get_wss_name(wlp, ptr, info->name, buflen);
419 if (result < 0) {
420 dev_err(dev, "WLP: unable to obtain WSS name from "
421 "WSS info in D2 message.\n");
422 goto error_parse;
423 }
424 used += result;
425 d_printf(6, dev, "WLP: WSS info: Retrieving accept enroll\n");
426 result = wlp_get_accept_enrl(wlp, ptr + used, &info->accept_enroll,
427 buflen - used);
428 if (result < 0) {
429 dev_err(dev, "WLP: unable to obtain accepting "
430 "enrollment from WSS info in D2 message.\n");
431 goto error_parse;
432 }
433 if (info->accept_enroll != 0 && info->accept_enroll != 1) {
434 dev_err(dev, "WLP: invalid value for accepting "
435 "enrollment in D2 message.\n");
436 result = -EINVAL;
437 goto error_parse;
438 }
439 used += result;
440 d_printf(6, dev, "WLP: WSS info: Retrieving secure status\n");
441 result = wlp_get_wss_sec_status(wlp, ptr + used, &info->sec_status,
442 buflen - used);
443 if (result < 0) {
444 dev_err(dev, "WLP: unable to obtain secure "
445 "status from WSS info in D2 message.\n");
446 goto error_parse;
447 }
448 if (info->sec_status != 0 && info->sec_status != 1) {
449 dev_err(dev, "WLP: invalid value for secure "
450 "status in D2 message.\n");
451 result = -EINVAL;
452 goto error_parse;
453 }
454 used += result;
455 d_printf(6, dev, "WLP: WSS info: Retrieving broadcast\n");
456 result = wlp_get_wss_bcast(wlp, ptr + used, &info->bcast,
457 buflen - used);
458 if (result < 0) {
459 dev_err(dev, "WLP: unable to obtain broadcast "
460 "address from WSS info in D2 message.\n");
461 goto error_parse;
462 }
463 used += result;
464 result = used;
465error_parse:
466 return result;
467}
468
469
470
471
472
473
474
475
476
477
478
479
480static struct wlp_wssid_e *wlp_create_wssid_e(struct wlp *wlp,
481 struct wlp_neighbor_e *neighbor)
482{
483 struct device *dev = &wlp->rc->uwb_dev.dev;
484 struct wlp_wssid_e *wssid_e;
485
486 wssid_e = kzalloc(sizeof(*wssid_e), GFP_KERNEL);
487 if (wssid_e == NULL) {
488 dev_err(dev, "WLP: unable to allocate memory "
489 "for WSS information.\n");
490 goto error_alloc;
491 }
492 wssid_e->info = kzalloc(sizeof(struct wlp_wss_tmp_info), GFP_KERNEL);
493 if (wssid_e->info == NULL) {
494 dev_err(dev, "WLP: unable to allocate memory "
495 "for temporary WSS information.\n");
496 kfree(wssid_e);
497 wssid_e = NULL;
498 goto error_alloc;
499 }
500 list_add(&wssid_e->node, &neighbor->wssid);
501error_alloc:
502 return wssid_e;
503}
504
505
506
507
508
509
510
511
512
513
514
515
516static ssize_t wlp_get_wss_info(struct wlp *wlp, struct wlp_attr_wss_info *attr,
517 size_t buflen, struct wlp_uuid *wssid,
518 struct wlp_wss_tmp_info *wss_info)
519{
520 struct device *dev = &wlp->rc->uwb_dev.dev;
521 ssize_t result;
522 size_t len;
523 size_t used = 0;
524 void *ptr;
525
526 result = wlp_check_wss_info_attr_hdr(wlp, (struct wlp_attr_hdr *)attr,
527 buflen);
528 if (result < 0)
529 goto out;
530 len = result;
531 used = sizeof(*attr);
532 ptr = attr;
533 d_printf(6, dev, "WLP: WSS info: Retrieving WSSID\n");
534 result = wlp_get_wssid(wlp, ptr + used, wssid, buflen - used);
535 if (result < 0) {
536 dev_err(dev, "WLP: unable to obtain WSSID from WSS info.\n");
537 goto out;
538 }
539 used += result;
540 result = wlp_get_wss_info_attrs(wlp, ptr + used, wss_info,
541 buflen - used);
542 if (result < 0) {
543 dev_err(dev, "WLP: unable to obtain WSS information "
544 "from WSS information attributes. \n");
545 goto out;
546 }
547 used += result;
548 if (len + sizeof(*attr) != used) {
549 dev_err(dev, "WLP: Amount of data parsed does not "
550 "match length field. Parsed %zu, length "
551 "field %zu. \n", used, len);
552 result = -EINVAL;
553 goto out;
554 }
555 result = used;
556 d_printf(6, dev, "WLP: Successfully parsed WLP information "
557 "attribute. used %zu bytes\n", used);
558out:
559 return result;
560}
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586static ssize_t wlp_get_all_wss_info(struct wlp *wlp,
587 struct wlp_attr_wss_info *attr,
588 struct wlp_neighbor_e *neighbor,
589 struct wlp_wss *wss, ssize_t buflen)
590{
591 struct device *dev = &wlp->rc->uwb_dev.dev;
592 size_t used = 0;
593 ssize_t result = -EINVAL;
594 struct wlp_attr_wss_info *cur;
595 struct wlp_uuid wssid;
596 struct wlp_wss_tmp_info wss_info;
597 unsigned enroll;
598 struct wlp_wssid_e *wssid_e;
599 char buf[WLP_WSS_UUID_STRSIZE];
600
601 d_fnstart(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d \n",
602 wlp, attr, neighbor, wss, (int)buflen);
603 if (buflen < 0)
604 goto out;
605
606 if (neighbor != NULL && wss == NULL)
607 enroll = 0;
608 else if (wss != NULL && neighbor == NULL)
609 enroll = 1;
610 else
611 goto out;
612
613 cur = attr;
614 while (buflen - used > 0) {
615 memset(&wss_info, 0, sizeof(wss_info));
616 cur = (void *)cur + used;
617 result = wlp_get_wss_info(wlp, cur, buflen - used, &wssid,
618 &wss_info);
619 if (result == -ENODATA) {
620 result = used;
621 goto out;
622 } else if (result < 0) {
623 dev_err(dev, "WLP: Unable to parse WSS information "
624 "from WSS information attribute. \n");
625 result = -EINVAL;
626 goto error_parse;
627 }
628 if (enroll && !memcmp(&wssid, &wss->wssid, sizeof(wssid))) {
629 if (wss_info.accept_enroll != 1) {
630 dev_err(dev, "WLP: Requested WSS does "
631 "not accept enrollment.\n");
632 result = -EINVAL;
633 goto out;
634 }
635 memcpy(wss->name, wss_info.name, sizeof(wss->name));
636 wss->bcast = wss_info.bcast;
637 wss->secure_status = wss_info.sec_status;
638 wss->accept_enroll = wss_info.accept_enroll;
639 wss->state = WLP_WSS_STATE_PART_ENROLLED;
640 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
641 d_printf(2, dev, "WLP: Found WSS %s. Enrolling.\n",
642 buf);
643 } else {
644 wssid_e = wlp_create_wssid_e(wlp, neighbor);
645 if (wssid_e == NULL) {
646 dev_err(dev, "WLP: Cannot create new WSSID "
647 "entry for neighbor %02x:%02x.\n",
648 neighbor->uwb_dev->dev_addr.data[1],
649 neighbor->uwb_dev->dev_addr.data[0]);
650 result = -ENOMEM;
651 goto out;
652 }
653 wssid_e->wssid = wssid;
654 *wssid_e->info = wss_info;
655 }
656 used += result;
657 }
658 result = used;
659error_parse:
660 if (result < 0 && !enroll)
661 wlp_remove_neighbor_tmp_info(neighbor);
662out:
663 d_fnend(6, dev, "wlp %p, attr %p, neighbor %p, wss %p, buflen %d, "
664 "result %d \n", wlp, attr, neighbor, wss, (int)buflen,
665 (int)result);
666 return result;
667
668}
669
670
671
672
673
674
675
676
677static ssize_t wlp_get_wss_info_to_cache(struct wlp *wlp,
678 struct wlp_attr_wss_info *attr,
679 struct wlp_neighbor_e *neighbor,
680 ssize_t buflen)
681{
682 return wlp_get_all_wss_info(wlp, attr, neighbor, NULL, buflen);
683}
684
685
686
687
688
689
690
691
692static ssize_t wlp_get_wss_info_to_enroll(struct wlp *wlp,
693 struct wlp_attr_wss_info *attr,
694 struct wlp_wss *wss, ssize_t buflen)
695{
696 return wlp_get_all_wss_info(wlp, attr, NULL, wss, buflen);
697}
698
699
700
701
702
703
704
705
706
707
708
709static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
710 struct sk_buff **skb)
711{
712
713 struct device *dev = &wlp->rc->uwb_dev.dev;
714 int result = 0;
715 struct wlp_device_info *info;
716 size_t used = 0;
717 struct wlp_frame_assoc *_d1;
718 struct sk_buff *_skb;
719 void *d1_itr;
720
721 d_fnstart(6, dev, "wlp %p\n", wlp);
722 if (wlp->dev_info == NULL) {
723 result = __wlp_setup_device_info(wlp);
724 if (result < 0) {
725 dev_err(dev, "WLP: Unable to setup device "
726 "information for D1 message.\n");
727 goto error;
728 }
729 }
730 info = wlp->dev_info;
731 d_printf(6, dev, "Local properties:\n"
732 "Device name (%d bytes): %s\n"
733 "Model name (%d bytes): %s\n"
734 "Manufacturer (%d bytes): %s\n"
735 "Model number (%d bytes): %s\n"
736 "Serial number (%d bytes): %s\n"
737 "Primary device type: \n"
738 " Category: %d \n"
739 " OUI: %02x:%02x:%02x \n"
740 " OUI Subdivision: %u \n",
741 (int)strlen(info->name), info->name,
742 (int)strlen(info->model_name), info->model_name,
743 (int)strlen(info->manufacturer), info->manufacturer,
744 (int)strlen(info->model_nr), info->model_nr,
745 (int)strlen(info->serial), info->serial,
746 info->prim_dev_type.category,
747 info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
748 info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
749 _skb = dev_alloc_skb(sizeof(*_d1)
750 + sizeof(struct wlp_attr_uuid_e)
751 + sizeof(struct wlp_attr_wss_sel_mthd)
752 + sizeof(struct wlp_attr_dev_name)
753 + strlen(info->name)
754 + sizeof(struct wlp_attr_manufacturer)
755 + strlen(info->manufacturer)
756 + sizeof(struct wlp_attr_model_name)
757 + strlen(info->model_name)
758 + sizeof(struct wlp_attr_model_nr)
759 + strlen(info->model_nr)
760 + sizeof(struct wlp_attr_serial)
761 + strlen(info->serial)
762 + sizeof(struct wlp_attr_prim_dev_type)
763 + sizeof(struct wlp_attr_wlp_assc_err));
764 if (_skb == NULL) {
765 dev_err(dev, "WLP: Cannot allocate memory for association "
766 "message.\n");
767 result = -ENOMEM;
768 goto error;
769 }
770 _d1 = (void *) _skb->data;
771 d_printf(6, dev, "D1 starts at %p \n", _d1);
772 _d1->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
773 _d1->hdr.type = WLP_FRAME_ASSOCIATION;
774 _d1->type = WLP_ASSOC_D1;
775
776 wlp_set_version(&_d1->version, WLP_VERSION);
777 wlp_set_msg_type(&_d1->msg_type, WLP_ASSOC_D1);
778 d1_itr = _d1->attr;
779 used = wlp_set_uuid_e(d1_itr, &wlp->uuid);
780 used += wlp_set_wss_sel_mthd(d1_itr + used, WLP_WSS_REG_SELECT);
781 used += wlp_set_dev_name(d1_itr + used, info->name,
782 strlen(info->name));
783 used += wlp_set_manufacturer(d1_itr + used, info->manufacturer,
784 strlen(info->manufacturer));
785 used += wlp_set_model_name(d1_itr + used, info->model_name,
786 strlen(info->model_name));
787 used += wlp_set_model_nr(d1_itr + used, info->model_nr,
788 strlen(info->model_nr));
789 used += wlp_set_serial(d1_itr + used, info->serial,
790 strlen(info->serial));
791 used += wlp_set_prim_dev_type(d1_itr + used, &info->prim_dev_type);
792 used += wlp_set_wlp_assc_err(d1_itr + used, WLP_ASSOC_ERROR_NONE);
793 skb_put(_skb, sizeof(*_d1) + used);
794 d_printf(6, dev, "D1 message:\n");
795 d_dump(6, dev, _d1, sizeof(*_d1)
796 + sizeof(struct wlp_attr_uuid_e)
797 + sizeof(struct wlp_attr_wss_sel_mthd)
798 + sizeof(struct wlp_attr_dev_name)
799 + strlen(info->name)
800 + sizeof(struct wlp_attr_manufacturer)
801 + strlen(info->manufacturer)
802 + sizeof(struct wlp_attr_model_name)
803 + strlen(info->model_name)
804 + sizeof(struct wlp_attr_model_nr)
805 + strlen(info->model_nr)
806 + sizeof(struct wlp_attr_serial)
807 + strlen(info->serial)
808 + sizeof(struct wlp_attr_prim_dev_type)
809 + sizeof(struct wlp_attr_wlp_assc_err));
810 *skb = _skb;
811error:
812 d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
813 return result;
814}
815
816
817
818
819
820
821
822
823
824
825
826static
827int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
828 struct sk_buff **skb, struct wlp_uuid *uuid_e)
829{
830
831 struct device *dev = &wlp->rc->uwb_dev.dev;
832 int result = 0;
833 struct wlp_device_info *info;
834 size_t used = 0;
835 struct wlp_frame_assoc *_d2;
836 struct sk_buff *_skb;
837 void *d2_itr;
838 size_t mem_needed;
839
840 d_fnstart(6, dev, "wlp %p\n", wlp);
841 if (wlp->dev_info == NULL) {
842 result = __wlp_setup_device_info(wlp);
843 if (result < 0) {
844 dev_err(dev, "WLP: Unable to setup device "
845 "information for D2 message.\n");
846 goto error;
847 }
848 }
849 info = wlp->dev_info;
850 d_printf(6, dev, "Local properties:\n"
851 "Device name (%d bytes): %s\n"
852 "Model name (%d bytes): %s\n"
853 "Manufacturer (%d bytes): %s\n"
854 "Model number (%d bytes): %s\n"
855 "Serial number (%d bytes): %s\n"
856 "Primary device type: \n"
857 " Category: %d \n"
858 " OUI: %02x:%02x:%02x \n"
859 " OUI Subdivision: %u \n",
860 (int)strlen(info->name), info->name,
861 (int)strlen(info->model_name), info->model_name,
862 (int)strlen(info->manufacturer), info->manufacturer,
863 (int)strlen(info->model_nr), info->model_nr,
864 (int)strlen(info->serial), info->serial,
865 info->prim_dev_type.category,
866 info->prim_dev_type.OUI[0], info->prim_dev_type.OUI[1],
867 info->prim_dev_type.OUI[2], info->prim_dev_type.OUIsubdiv);
868 mem_needed = sizeof(*_d2)
869 + sizeof(struct wlp_attr_uuid_e)
870 + sizeof(struct wlp_attr_uuid_r)
871 + sizeof(struct wlp_attr_dev_name)
872 + strlen(info->name)
873 + sizeof(struct wlp_attr_manufacturer)
874 + strlen(info->manufacturer)
875 + sizeof(struct wlp_attr_model_name)
876 + strlen(info->model_name)
877 + sizeof(struct wlp_attr_model_nr)
878 + strlen(info->model_nr)
879 + sizeof(struct wlp_attr_serial)
880 + strlen(info->serial)
881 + sizeof(struct wlp_attr_prim_dev_type)
882 + sizeof(struct wlp_attr_wlp_assc_err);
883 if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
884 mem_needed += sizeof(struct wlp_attr_wss_info)
885 + sizeof(struct wlp_wss_info)
886 + strlen(wlp->wss.name);
887 _skb = dev_alloc_skb(mem_needed);
888 if (_skb == NULL) {
889 dev_err(dev, "WLP: Cannot allocate memory for association "
890 "message.\n");
891 result = -ENOMEM;
892 goto error;
893 }
894 _d2 = (void *) _skb->data;
895 d_printf(6, dev, "D2 starts at %p \n", _d2);
896 _d2->hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
897 _d2->hdr.type = WLP_FRAME_ASSOCIATION;
898 _d2->type = WLP_ASSOC_D2;
899
900 wlp_set_version(&_d2->version, WLP_VERSION);
901 wlp_set_msg_type(&_d2->msg_type, WLP_ASSOC_D2);
902 d2_itr = _d2->attr;
903 used = wlp_set_uuid_e(d2_itr, uuid_e);
904 used += wlp_set_uuid_r(d2_itr + used, &wlp->uuid);
905 if (wlp->wss.state >= WLP_WSS_STATE_ACTIVE)
906 used += wlp_set_wss_info(d2_itr + used, &wlp->wss);
907 used += wlp_set_dev_name(d2_itr + used, info->name,
908 strlen(info->name));
909 used += wlp_set_manufacturer(d2_itr + used, info->manufacturer,
910 strlen(info->manufacturer));
911 used += wlp_set_model_name(d2_itr + used, info->model_name,
912 strlen(info->model_name));
913 used += wlp_set_model_nr(d2_itr + used, info->model_nr,
914 strlen(info->model_nr));
915 used += wlp_set_serial(d2_itr + used, info->serial,
916 strlen(info->serial));
917 used += wlp_set_prim_dev_type(d2_itr + used, &info->prim_dev_type);
918 used += wlp_set_wlp_assc_err(d2_itr + used, WLP_ASSOC_ERROR_NONE);
919 skb_put(_skb, sizeof(*_d2) + used);
920 d_printf(6, dev, "D2 message:\n");
921 d_dump(6, dev, _d2, mem_needed);
922 *skb = _skb;
923error:
924 d_fnend(6, dev, "wlp %p, result = %d\n", wlp, result);
925 return result;
926}
927
928
929
930
931
932
933
934
935static
936int wlp_build_assoc_f0(struct wlp *wlp, struct sk_buff **skb,
937 enum wlp_assc_error error)
938{
939 struct device *dev = &wlp->rc->uwb_dev.dev;
940 int result = -ENOMEM;
941 struct {
942 struct wlp_frame_assoc f0_hdr;
943 struct wlp_attr_enonce enonce;
944 struct wlp_attr_rnonce rnonce;
945 struct wlp_attr_wlp_assc_err assc_err;
946 } *f0;
947 struct sk_buff *_skb;
948 struct wlp_nonce tmp;
949
950 d_fnstart(6, dev, "wlp %p\n", wlp);
951 _skb = dev_alloc_skb(sizeof(*f0));
952 if (_skb == NULL) {
953 dev_err(dev, "WLP: Unable to allocate memory for F0 "
954 "association frame. \n");
955 goto error_alloc;
956 }
957 f0 = (void *) _skb->data;
958 d_printf(6, dev, "F0 starts at %p \n", f0);
959 f0->f0_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
960 f0->f0_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
961 f0->f0_hdr.type = WLP_ASSOC_F0;
962 wlp_set_version(&f0->f0_hdr.version, WLP_VERSION);
963 wlp_set_msg_type(&f0->f0_hdr.msg_type, WLP_ASSOC_F0);
964 memset(&tmp, 0, sizeof(tmp));
965 wlp_set_enonce(&f0->enonce, &tmp);
966 wlp_set_rnonce(&f0->rnonce, &tmp);
967 wlp_set_wlp_assc_err(&f0->assc_err, error);
968 skb_put(_skb, sizeof(*f0));
969 *skb = _skb;
970 result = 0;
971error_alloc:
972 d_fnend(6, dev, "wlp %p, result %d \n", wlp, result);
973 return result;
974}
975
976
977
978
979
980
981
982
983int wlp_parse_f0(struct wlp *wlp, struct sk_buff *skb)
984{
985 struct device *dev = &wlp->rc->uwb_dev.dev;
986 struct wlp_frame_assoc *f0 = (void *) skb->data;
987 void *ptr = skb->data;
988 size_t len = skb->len;
989 size_t used;
990 ssize_t result;
991 struct wlp_nonce enonce, rnonce;
992 enum wlp_assc_error assc_err;
993 char enonce_buf[WLP_WSS_NONCE_STRSIZE];
994 char rnonce_buf[WLP_WSS_NONCE_STRSIZE];
995
996 used = sizeof(*f0);
997 result = wlp_get_enonce(wlp, ptr + used, &enonce, len - used);
998 if (result < 0) {
999 dev_err(dev, "WLP: unable to obtain Enrollee nonce "
1000 "attribute from F0 message.\n");
1001 goto error_parse;
1002 }
1003 used += result;
1004 result = wlp_get_rnonce(wlp, ptr + used, &rnonce, len - used);
1005 if (result < 0) {
1006 dev_err(dev, "WLP: unable to obtain Registrar nonce "
1007 "attribute from F0 message.\n");
1008 goto error_parse;
1009 }
1010 used += result;
1011 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1012 if (result < 0) {
1013 dev_err(dev, "WLP: unable to obtain WLP Association error "
1014 "attribute from F0 message.\n");
1015 goto error_parse;
1016 }
1017 wlp_wss_nonce_print(enonce_buf, sizeof(enonce_buf), &enonce);
1018 wlp_wss_nonce_print(rnonce_buf, sizeof(rnonce_buf), &rnonce);
1019 dev_err(dev, "WLP: Received F0 error frame from neighbor. Enrollee "
1020 "nonce: %s, Registrar nonce: %s, WLP Association error: %s.\n",
1021 enonce_buf, rnonce_buf, wlp_assc_error_str(assc_err));
1022 result = 0;
1023error_parse:
1024 return result;
1025}
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040static
1041int wlp_get_variable_info(struct wlp *wlp, void *data,
1042 struct wlp_device_info *dev_info, ssize_t len)
1043{
1044 struct device *dev = &wlp->rc->uwb_dev.dev;
1045 size_t used = 0;
1046 struct wlp_attr_hdr *hdr;
1047 ssize_t result = 0;
1048 unsigned last = 0;
1049
1050 while (len - used > 0) {
1051 if (len - used < sizeof(*hdr)) {
1052 dev_err(dev, "WLP: Partial data in frame, cannot "
1053 "parse. \n");
1054 goto error_parse;
1055 }
1056 hdr = data + used;
1057 switch (le16_to_cpu(hdr->type)) {
1058 case WLP_ATTR_MANUF:
1059 if (last >= WLP_ATTR_MANUF) {
1060 dev_err(dev, "WLP: Incorrect order of "
1061 "attribute values in D1 msg.\n");
1062 goto error_parse;
1063 }
1064 result = wlp_get_manufacturer(wlp, data + used,
1065 dev_info->manufacturer,
1066 len - used);
1067 if (result < 0) {
1068 dev_err(dev, "WLP: Unable to obtain "
1069 "Manufacturer attribute from D1 "
1070 "message.\n");
1071 goto error_parse;
1072 }
1073 last = WLP_ATTR_MANUF;
1074 used += result;
1075 break;
1076 case WLP_ATTR_MODEL_NAME:
1077 if (last >= WLP_ATTR_MODEL_NAME) {
1078 dev_err(dev, "WLP: Incorrect order of "
1079 "attribute values in D1 msg.\n");
1080 goto error_parse;
1081 }
1082 result = wlp_get_model_name(wlp, data + used,
1083 dev_info->model_name,
1084 len - used);
1085 if (result < 0) {
1086 dev_err(dev, "WLP: Unable to obtain Model "
1087 "name attribute from D1 message.\n");
1088 goto error_parse;
1089 }
1090 last = WLP_ATTR_MODEL_NAME;
1091 used += result;
1092 break;
1093 case WLP_ATTR_MODEL_NR:
1094 if (last >= WLP_ATTR_MODEL_NR) {
1095 dev_err(dev, "WLP: Incorrect order of "
1096 "attribute values in D1 msg.\n");
1097 goto error_parse;
1098 }
1099 result = wlp_get_model_nr(wlp, data + used,
1100 dev_info->model_nr,
1101 len - used);
1102 if (result < 0) {
1103 dev_err(dev, "WLP: Unable to obtain Model "
1104 "number attribute from D1 message.\n");
1105 goto error_parse;
1106 }
1107 last = WLP_ATTR_MODEL_NR;
1108 used += result;
1109 break;
1110 case WLP_ATTR_SERIAL:
1111 if (last >= WLP_ATTR_SERIAL) {
1112 dev_err(dev, "WLP: Incorrect order of "
1113 "attribute values in D1 msg.\n");
1114 goto error_parse;
1115 }
1116 result = wlp_get_serial(wlp, data + used,
1117 dev_info->serial, len - used);
1118 if (result < 0) {
1119 dev_err(dev, "WLP: Unable to obtain Serial "
1120 "number attribute from D1 message.\n");
1121 goto error_parse;
1122 }
1123 last = WLP_ATTR_SERIAL;
1124 used += result;
1125 break;
1126 case WLP_ATTR_PRI_DEV_TYPE:
1127 if (last >= WLP_ATTR_PRI_DEV_TYPE) {
1128 dev_err(dev, "WLP: Incorrect order of "
1129 "attribute values in D1 msg.\n");
1130 goto error_parse;
1131 }
1132 result = wlp_get_prim_dev_type(wlp, data + used,
1133 &dev_info->prim_dev_type,
1134 len - used);
1135 if (result < 0) {
1136 dev_err(dev, "WLP: Unable to obtain Primary "
1137 "device type attribute from D1 "
1138 "message.\n");
1139 goto error_parse;
1140 }
1141 dev_info->prim_dev_type.category =
1142 le16_to_cpu(dev_info->prim_dev_type.category);
1143 dev_info->prim_dev_type.subID =
1144 le16_to_cpu(dev_info->prim_dev_type.subID);
1145 last = WLP_ATTR_PRI_DEV_TYPE;
1146 used += result;
1147 break;
1148 default:
1149
1150 goto out;
1151 break;
1152 }
1153 }
1154out:
1155 return used;
1156error_parse:
1157 return -EINVAL;
1158}
1159
1160
1161
1162
1163
1164
1165
1166static
1167int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
1168 struct wlp_uuid *uuid_e,
1169 enum wlp_wss_sel_mthd *sel_mthd,
1170 struct wlp_device_info *dev_info,
1171 enum wlp_assc_error *assc_err)
1172{
1173 struct device *dev = &wlp->rc->uwb_dev.dev;
1174 struct wlp_frame_assoc *d1 = (void *) skb->data;
1175 void *ptr = skb->data;
1176 size_t len = skb->len;
1177 size_t used;
1178 ssize_t result;
1179
1180 used = sizeof(*d1);
1181 result = wlp_get_uuid_e(wlp, ptr + used, uuid_e, len - used);
1182 if (result < 0) {
1183 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D1 "
1184 "message.\n");
1185 goto error_parse;
1186 }
1187 used += result;
1188 result = wlp_get_wss_sel_mthd(wlp, ptr + used, sel_mthd, len - used);
1189 if (result < 0) {
1190 dev_err(dev, "WLP: unable to obtain WSS selection method "
1191 "from D1 message.\n");
1192 goto error_parse;
1193 }
1194 used += result;
1195 result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
1196 len - used);
1197 if (result < 0) {
1198 dev_err(dev, "WLP: unable to obtain Device Name from D1 "
1199 "message.\n");
1200 goto error_parse;
1201 }
1202 used += result;
1203 result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
1204 if (result < 0) {
1205 dev_err(dev, "WLP: unable to obtain Device Information from "
1206 "D1 message.\n");
1207 goto error_parse;
1208 }
1209 used += result;
1210 result = wlp_get_wlp_assc_err(wlp, ptr + used, assc_err, len - used);
1211 if (result < 0) {
1212 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1213 "Information from D1 message.\n");
1214 goto error_parse;
1215 }
1216 result = 0;
1217error_parse:
1218 return result;
1219}
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230void wlp_handle_d1_frame(struct work_struct *ws)
1231{
1232 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1233 struct wlp_assoc_frame_ctx,
1234 ws);
1235 struct wlp *wlp = frame_ctx->wlp;
1236 struct wlp_wss *wss = &wlp->wss;
1237 struct sk_buff *skb = frame_ctx->skb;
1238 struct uwb_dev_addr *src = &frame_ctx->src;
1239 int result;
1240 struct device *dev = &wlp->rc->uwb_dev.dev;
1241 struct wlp_uuid uuid_e;
1242 enum wlp_wss_sel_mthd sel_mthd = 0;
1243 struct wlp_device_info dev_info;
1244 enum wlp_assc_error assc_err;
1245 char uuid[WLP_WSS_UUID_STRSIZE];
1246 struct sk_buff *resp = NULL;
1247
1248
1249 d_fnstart(6, dev, "WLP: handle D1 frame. wlp = %p, skb = %p\n",
1250 wlp, skb);
1251 mutex_lock(&wss->mutex);
1252 mutex_lock(&wlp->mutex);
1253 memset(&dev_info, 0, sizeof(dev_info));
1254 result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
1255 &assc_err);
1256 if (result < 0) {
1257 dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
1258 kfree_skb(skb);
1259 goto out;
1260 }
1261 wlp_wss_uuid_print(uuid, sizeof(uuid), &uuid_e);
1262 d_printf(6, dev, "From D1 frame:\n"
1263 "UUID-E: %s\n"
1264 "Selection method: %d\n"
1265 "Device name (%d bytes): %s\n"
1266 "Model name (%d bytes): %s\n"
1267 "Manufacturer (%d bytes): %s\n"
1268 "Model number (%d bytes): %s\n"
1269 "Serial number (%d bytes): %s\n"
1270 "Primary device type: \n"
1271 " Category: %d \n"
1272 " OUI: %02x:%02x:%02x \n"
1273 " OUI Subdivision: %u \n",
1274 uuid, sel_mthd,
1275 (int)strlen(dev_info.name), dev_info.name,
1276 (int)strlen(dev_info.model_name), dev_info.model_name,
1277 (int)strlen(dev_info.manufacturer), dev_info.manufacturer,
1278 (int)strlen(dev_info.model_nr), dev_info.model_nr,
1279 (int)strlen(dev_info.serial), dev_info.serial,
1280 dev_info.prim_dev_type.category,
1281 dev_info.prim_dev_type.OUI[0],
1282 dev_info.prim_dev_type.OUI[1],
1283 dev_info.prim_dev_type.OUI[2],
1284 dev_info.prim_dev_type.OUIsubdiv);
1285
1286 kfree_skb(skb);
1287 if (!wlp_uuid_is_set(&wlp->uuid)) {
1288 dev_err(dev, "WLP: UUID is not set. Set via sysfs to "
1289 "proceed. Respong to D1 message with error F0.\n");
1290 result = wlp_build_assoc_f0(wlp, &resp,
1291 WLP_ASSOC_ERROR_NOT_READY);
1292 if (result < 0) {
1293 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1294 goto out;
1295 }
1296 } else {
1297
1298 result = wlp_build_assoc_d2(wlp, wss, &resp, &uuid_e);
1299 if (result < 0) {
1300 dev_err(dev, "WLP: Unable to construct D2 message.\n");
1301 goto out;
1302 }
1303 }
1304
1305 BUG_ON(wlp->xmit_frame == NULL);
1306 result = wlp->xmit_frame(wlp, resp, src);
1307 if (result < 0) {
1308 dev_err(dev, "WLP: Unable to transmit D2 association "
1309 "message: %d\n", result);
1310 if (result == -ENXIO)
1311 dev_err(dev, "WLP: Is network interface up? \n");
1312
1313 dev_kfree_skb_any(resp);
1314 }
1315out:
1316 kfree(frame_ctx);
1317 mutex_unlock(&wlp->mutex);
1318 mutex_unlock(&wss->mutex);
1319 d_fnend(6, dev, "WLP: handle D1 frame. wlp = %p\n", wlp);
1320}
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331int wlp_parse_d2_frame_to_cache(struct wlp *wlp, struct sk_buff *skb,
1332 struct wlp_neighbor_e *neighbor)
1333{
1334 struct device *dev = &wlp->rc->uwb_dev.dev;
1335 struct wlp_frame_assoc *d2 = (void *) skb->data;
1336 void *ptr = skb->data;
1337 size_t len = skb->len;
1338 size_t used;
1339 ssize_t result;
1340 struct wlp_uuid uuid_e;
1341 struct wlp_device_info *nb_info;
1342 enum wlp_assc_error assc_err;
1343
1344 used = sizeof(*d2);
1345 result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
1346 if (result < 0) {
1347 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
1348 "message.\n");
1349 goto error_parse;
1350 }
1351 if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
1352 dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
1353 "local UUID sent in D1. \n");
1354 goto error_parse;
1355 }
1356 used += result;
1357 result = wlp_get_uuid_r(wlp, ptr + used, &neighbor->uuid, len - used);
1358 if (result < 0) {
1359 dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
1360 "message.\n");
1361 goto error_parse;
1362 }
1363 used += result;
1364 result = wlp_get_wss_info_to_cache(wlp, ptr + used, neighbor,
1365 len - used);
1366 if (result < 0) {
1367 dev_err(dev, "WLP: unable to obtain WSS information "
1368 "from D2 message.\n");
1369 goto error_parse;
1370 }
1371 used += result;
1372 neighbor->info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
1373 if (neighbor->info == NULL) {
1374 dev_err(dev, "WLP: cannot allocate memory to store device "
1375 "info.\n");
1376 result = -ENOMEM;
1377 goto error_parse;
1378 }
1379 nb_info = neighbor->info;
1380 result = wlp_get_dev_name(wlp, ptr + used, nb_info->name,
1381 len - used);
1382 if (result < 0) {
1383 dev_err(dev, "WLP: unable to obtain Device Name from D2 "
1384 "message.\n");
1385 goto error_parse;
1386 }
1387 used += result;
1388 result = wlp_get_variable_info(wlp, ptr + used, nb_info, len - used);
1389 if (result < 0) {
1390 dev_err(dev, "WLP: unable to obtain Device Information from "
1391 "D2 message.\n");
1392 goto error_parse;
1393 }
1394 used += result;
1395 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1396 if (result < 0) {
1397 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1398 "Information from D2 message.\n");
1399 goto error_parse;
1400 }
1401 if (assc_err != WLP_ASSOC_ERROR_NONE) {
1402 dev_err(dev, "WLP: neighbor device returned association "
1403 "error %d\n", assc_err);
1404 result = -EINVAL;
1405 goto error_parse;
1406 }
1407 result = 0;
1408error_parse:
1409 if (result < 0)
1410 wlp_remove_neighbor_tmp_info(neighbor);
1411 return result;
1412}
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428int wlp_parse_d2_frame_to_enroll(struct wlp_wss *wss, struct sk_buff *skb,
1429 struct wlp_neighbor_e *neighbor,
1430 struct wlp_uuid *wssid)
1431{
1432 struct wlp *wlp = container_of(wss, struct wlp, wss);
1433 struct device *dev = &wlp->rc->uwb_dev.dev;
1434 void *ptr = skb->data;
1435 size_t len = skb->len;
1436 size_t used;
1437 ssize_t result;
1438 struct wlp_uuid uuid_e;
1439 struct wlp_uuid uuid_r;
1440 struct wlp_device_info nb_info;
1441 enum wlp_assc_error assc_err;
1442 char uuid_bufA[WLP_WSS_UUID_STRSIZE];
1443 char uuid_bufB[WLP_WSS_UUID_STRSIZE];
1444
1445 used = sizeof(struct wlp_frame_assoc);
1446 result = wlp_get_uuid_e(wlp, ptr + used, &uuid_e, len - used);
1447 if (result < 0) {
1448 dev_err(dev, "WLP: unable to obtain UUID-E attribute from D2 "
1449 "message.\n");
1450 goto error_parse;
1451 }
1452 if (memcmp(&uuid_e, &wlp->uuid, sizeof(uuid_e))) {
1453 dev_err(dev, "WLP: UUID-E in incoming D2 does not match "
1454 "local UUID sent in D1. \n");
1455 goto error_parse;
1456 }
1457 used += result;
1458 result = wlp_get_uuid_r(wlp, ptr + used, &uuid_r, len - used);
1459 if (result < 0) {
1460 dev_err(dev, "WLP: unable to obtain UUID-R attribute from D2 "
1461 "message.\n");
1462 goto error_parse;
1463 }
1464 if (memcmp(&uuid_r, &neighbor->uuid, sizeof(uuid_r))) {
1465 wlp_wss_uuid_print(uuid_bufA, sizeof(uuid_bufA),
1466 &neighbor->uuid);
1467 wlp_wss_uuid_print(uuid_bufB, sizeof(uuid_bufB), &uuid_r);
1468 dev_err(dev, "WLP: UUID of neighbor does not match UUID "
1469 "learned during discovery. Originally discovered: %s, "
1470 "now from D2 message: %s\n", uuid_bufA, uuid_bufB);
1471 result = -EINVAL;
1472 goto error_parse;
1473 }
1474 used += result;
1475 wss->wssid = *wssid;
1476 result = wlp_get_wss_info_to_enroll(wlp, ptr + used, wss, len - used);
1477 if (result < 0) {
1478 dev_err(dev, "WLP: unable to obtain WSS information "
1479 "from D2 message.\n");
1480 goto error_parse;
1481 }
1482 if (wss->state != WLP_WSS_STATE_PART_ENROLLED) {
1483 dev_err(dev, "WLP: D2 message did not contain information "
1484 "for successful enrollment. \n");
1485 result = -EINVAL;
1486 goto error_parse;
1487 }
1488 used += result;
1489
1490 result = wlp_get_dev_name(wlp, ptr + used, nb_info.name,
1491 len - used);
1492 if (result < 0) {
1493 dev_err(dev, "WLP: unable to obtain Device Name from D2 "
1494 "message.\n");
1495 goto error_parse;
1496 }
1497 used += result;
1498 result = wlp_get_variable_info(wlp, ptr + used, &nb_info, len - used);
1499 if (result < 0) {
1500 dev_err(dev, "WLP: unable to obtain Device Information from "
1501 "D2 message.\n");
1502 goto error_parse;
1503 }
1504 used += result;
1505 result = wlp_get_wlp_assc_err(wlp, ptr + used, &assc_err, len - used);
1506 if (result < 0) {
1507 dev_err(dev, "WLP: unable to obtain WLP Association Error "
1508 "Information from D2 message.\n");
1509 goto error_parse;
1510 }
1511 if (assc_err != WLP_ASSOC_ERROR_NONE) {
1512 dev_err(dev, "WLP: neighbor device returned association "
1513 "error %d\n", assc_err);
1514 if (wss->state == WLP_WSS_STATE_PART_ENROLLED) {
1515 dev_err(dev, "WLP: Enrolled in WSS (should not "
1516 "happen according to spec). Undoing. \n");
1517 wlp_wss_reset(wss);
1518 }
1519 result = -EINVAL;
1520 goto error_parse;
1521 }
1522 result = 0;
1523error_parse:
1524 return result;
1525}
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540int wlp_parse_c3c4_frame(struct wlp *wlp, struct sk_buff *skb,
1541 struct wlp_uuid *wssid, u8 *tag,
1542 struct uwb_mac_addr *virt_addr)
1543{
1544 struct device *dev = &wlp->rc->uwb_dev.dev;
1545 int result;
1546 void *ptr = skb->data;
1547 size_t len = skb->len;
1548 size_t used;
1549 char buf[WLP_WSS_UUID_STRSIZE];
1550 struct wlp_frame_assoc *assoc = ptr;
1551
1552 d_fnstart(6, dev, "wlp %p, skb %p \n", wlp, skb);
1553 used = sizeof(*assoc);
1554 result = wlp_get_wssid(wlp, ptr + used, wssid, len - used);
1555 if (result < 0) {
1556 dev_err(dev, "WLP: unable to obtain WSSID attribute from "
1557 "%s message.\n", wlp_assoc_frame_str(assoc->type));
1558 goto error_parse;
1559 }
1560 used += result;
1561 result = wlp_get_wss_tag(wlp, ptr + used, tag, len - used);
1562 if (result < 0) {
1563 dev_err(dev, "WLP: unable to obtain WSS tag attribute from "
1564 "%s message.\n", wlp_assoc_frame_str(assoc->type));
1565 goto error_parse;
1566 }
1567 used += result;
1568 result = wlp_get_wss_virt(wlp, ptr + used, virt_addr, len - used);
1569 if (result < 0) {
1570 dev_err(dev, "WLP: unable to obtain WSS virtual address "
1571 "attribute from %s message.\n",
1572 wlp_assoc_frame_str(assoc->type));
1573 goto error_parse;
1574 }
1575 wlp_wss_uuid_print(buf, sizeof(buf), wssid);
1576 d_printf(6, dev, "WLP: parsed: WSSID %s, tag 0x%02x, virt "
1577 "%02x:%02x:%02x:%02x:%02x:%02x \n", buf, *tag,
1578 virt_addr->data[0], virt_addr->data[1], virt_addr->data[2],
1579 virt_addr->data[3], virt_addr->data[4], virt_addr->data[5]);
1580
1581error_parse:
1582 d_fnend(6, dev, "wlp %p, skb %p, result = %d \n", wlp, skb, result);
1583 return result;
1584}
1585
1586
1587
1588
1589
1590
1591static
1592int wlp_build_assoc_c1c2(struct wlp *wlp, struct wlp_wss *wss,
1593 struct sk_buff **skb, enum wlp_assoc_type type)
1594{
1595 struct device *dev = &wlp->rc->uwb_dev.dev;
1596 int result = -ENOMEM;
1597 struct {
1598 struct wlp_frame_assoc c_hdr;
1599 struct wlp_attr_wssid wssid;
1600 } *c;
1601 struct sk_buff *_skb;
1602
1603 d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
1604 _skb = dev_alloc_skb(sizeof(*c));
1605 if (_skb == NULL) {
1606 dev_err(dev, "WLP: Unable to allocate memory for C1/C2 "
1607 "association frame. \n");
1608 goto error_alloc;
1609 }
1610 c = (void *) _skb->data;
1611 d_printf(6, dev, "C1/C2 starts at %p \n", c);
1612 c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
1613 c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
1614 c->c_hdr.type = type;
1615 wlp_set_version(&c->c_hdr.version, WLP_VERSION);
1616 wlp_set_msg_type(&c->c_hdr.msg_type, type);
1617 wlp_set_wssid(&c->wssid, &wss->wssid);
1618 skb_put(_skb, sizeof(*c));
1619 d_printf(6, dev, "C1/C2 message:\n");
1620 d_dump(6, dev, c, sizeof(*c));
1621 *skb = _skb;
1622 result = 0;
1623error_alloc:
1624 d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
1625 return result;
1626}
1627
1628
1629static
1630int wlp_build_assoc_c1(struct wlp *wlp, struct wlp_wss *wss,
1631 struct sk_buff **skb)
1632{
1633 return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C1);
1634}
1635
1636static
1637int wlp_build_assoc_c2(struct wlp *wlp, struct wlp_wss *wss,
1638 struct sk_buff **skb)
1639{
1640 return wlp_build_assoc_c1c2(wlp, wss, skb, WLP_ASSOC_C2);
1641}
1642
1643
1644
1645
1646
1647
1648
1649static
1650int wlp_build_assoc_c3c4(struct wlp *wlp, struct wlp_wss *wss,
1651 struct sk_buff **skb, enum wlp_assoc_type type)
1652{
1653 struct device *dev = &wlp->rc->uwb_dev.dev;
1654 int result = -ENOMEM;
1655 struct {
1656 struct wlp_frame_assoc c_hdr;
1657 struct wlp_attr_wssid wssid;
1658 struct wlp_attr_wss_tag wss_tag;
1659 struct wlp_attr_wss_virt wss_virt;
1660 } *c;
1661 struct sk_buff *_skb;
1662
1663 d_fnstart(6, dev, "wlp %p, wss %p \n", wlp, wss);
1664 _skb = dev_alloc_skb(sizeof(*c));
1665 if (_skb == NULL) {
1666 dev_err(dev, "WLP: Unable to allocate memory for C3/C4 "
1667 "association frame. \n");
1668 goto error_alloc;
1669 }
1670 c = (void *) _skb->data;
1671 d_printf(6, dev, "C3/C4 starts at %p \n", c);
1672 c->c_hdr.hdr.mux_hdr = cpu_to_le16(WLP_PROTOCOL_ID);
1673 c->c_hdr.hdr.type = WLP_FRAME_ASSOCIATION;
1674 c->c_hdr.type = type;
1675 wlp_set_version(&c->c_hdr.version, WLP_VERSION);
1676 wlp_set_msg_type(&c->c_hdr.msg_type, type);
1677 wlp_set_wssid(&c->wssid, &wss->wssid);
1678 wlp_set_wss_tag(&c->wss_tag, wss->tag);
1679 wlp_set_wss_virt(&c->wss_virt, &wss->virtual_addr);
1680 skb_put(_skb, sizeof(*c));
1681 d_printf(6, dev, "C3/C4 message:\n");
1682 d_dump(6, dev, c, sizeof(*c));
1683 *skb = _skb;
1684 result = 0;
1685error_alloc:
1686 d_fnend(6, dev, "wlp %p, wss %p, result %d \n", wlp, wss, result);
1687 return result;
1688}
1689
1690static
1691int wlp_build_assoc_c3(struct wlp *wlp, struct wlp_wss *wss,
1692 struct sk_buff **skb)
1693{
1694 return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C3);
1695}
1696
1697static
1698int wlp_build_assoc_c4(struct wlp *wlp, struct wlp_wss *wss,
1699 struct sk_buff **skb)
1700{
1701 return wlp_build_assoc_c3c4(wlp, wss, skb, WLP_ASSOC_C4);
1702}
1703
1704
1705#define wlp_send_assoc(type, id) \
1706static int wlp_send_assoc_##type(struct wlp *wlp, struct wlp_wss *wss, \
1707 struct uwb_dev_addr *dev_addr) \
1708{ \
1709 struct device *dev = &wlp->rc->uwb_dev.dev; \
1710 int result; \
1711 struct sk_buff *skb = NULL; \
1712 d_fnstart(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
1713 wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
1714 d_printf(6, dev, "WLP: Constructing %s frame. \n", \
1715 wlp_assoc_frame_str(id)); \
1716 \
1717 result = wlp_build_assoc_##type(wlp, wss, &skb); \
1718 if (result < 0) { \
1719 dev_err(dev, "WLP: Unable to construct %s association " \
1720 "frame: %d\n", wlp_assoc_frame_str(id), result);\
1721 goto error_build_assoc; \
1722 } \
1723 \
1724 d_printf(6, dev, "Transmitting %s frame to %02x:%02x \n", \
1725 wlp_assoc_frame_str(id), \
1726 dev_addr->data[1], dev_addr->data[0]); \
1727 BUG_ON(wlp->xmit_frame == NULL); \
1728 result = wlp->xmit_frame(wlp, skb, dev_addr); \
1729 if (result < 0) { \
1730 dev_err(dev, "WLP: Unable to transmit %s association " \
1731 "message: %d\n", wlp_assoc_frame_str(id), \
1732 result); \
1733 if (result == -ENXIO) \
1734 dev_err(dev, "WLP: Is network interface " \
1735 "up? \n"); \
1736 goto error_xmit; \
1737 } \
1738 return 0; \
1739error_xmit: \
1740 \
1741 dev_kfree_skb_any(skb); \
1742error_build_assoc: \
1743 d_fnend(6, dev, "wlp %p, wss %p, neighbor: %02x:%02x\n", \
1744 wlp, wss, dev_addr->data[1], dev_addr->data[0]); \
1745 return result; \
1746}
1747
1748wlp_send_assoc(d1, WLP_ASSOC_D1)
1749wlp_send_assoc(c1, WLP_ASSOC_C1)
1750wlp_send_assoc(c3, WLP_ASSOC_C3)
1751
1752int wlp_send_assoc_frame(struct wlp *wlp, struct wlp_wss *wss,
1753 struct uwb_dev_addr *dev_addr,
1754 enum wlp_assoc_type type)
1755{
1756 int result = 0;
1757 struct device *dev = &wlp->rc->uwb_dev.dev;
1758 switch (type) {
1759 case WLP_ASSOC_D1:
1760 result = wlp_send_assoc_d1(wlp, wss, dev_addr);
1761 break;
1762 case WLP_ASSOC_C1:
1763 result = wlp_send_assoc_c1(wlp, wss, dev_addr);
1764 break;
1765 case WLP_ASSOC_C3:
1766 result = wlp_send_assoc_c3(wlp, wss, dev_addr);
1767 break;
1768 default:
1769 dev_err(dev, "WLP: Received request to send unknown "
1770 "association message.\n");
1771 result = -EINVAL;
1772 break;
1773 }
1774 return result;
1775}
1776
1777
1778
1779
1780
1781
1782
1783
1784void wlp_handle_c1_frame(struct work_struct *ws)
1785{
1786 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1787 struct wlp_assoc_frame_ctx,
1788 ws);
1789 struct wlp *wlp = frame_ctx->wlp;
1790 struct wlp_wss *wss = &wlp->wss;
1791 struct device *dev = &wlp->rc->uwb_dev.dev;
1792 struct wlp_frame_assoc *c1 = (void *) frame_ctx->skb->data;
1793 unsigned int len = frame_ctx->skb->len;
1794 struct uwb_dev_addr *src = &frame_ctx->src;
1795 int result;
1796 struct wlp_uuid wssid;
1797 char buf[WLP_WSS_UUID_STRSIZE];
1798 struct sk_buff *resp = NULL;
1799
1800
1801 d_fnstart(6, dev, "WLP: handle C1 frame. wlp = %p, c1 = %p\n",
1802 wlp, c1);
1803 mutex_lock(&wss->mutex);
1804 result = wlp_get_wssid(wlp, (void *)c1 + sizeof(*c1), &wssid,
1805 len - sizeof(*c1));
1806 if (result < 0) {
1807 dev_err(dev, "WLP: unable to obtain WSSID from C1 frame.\n");
1808 goto out;
1809 }
1810 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
1811 d_printf(6, dev, "Received C1 frame with WSSID %s \n", buf);
1812 if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
1813 && wss->state == WLP_WSS_STATE_ACTIVE) {
1814 d_printf(6, dev, "WSSID from C1 frame is known locally "
1815 "and is active\n");
1816
1817 result = wlp_build_assoc_c2(wlp, wss, &resp);
1818 if (result < 0) {
1819 dev_err(dev, "WLP: Unable to construct C2 message.\n");
1820 goto out;
1821 }
1822 } else {
1823 d_printf(6, dev, "WSSID from C1 frame is not known locally "
1824 "or is not active\n");
1825
1826 result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
1827 if (result < 0) {
1828 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1829 goto out;
1830 }
1831 }
1832
1833 d_printf(6, dev, "Transmitting response (C2/F0) frame to %02x:%02x \n",
1834 src->data[1], src->data[0]);
1835 BUG_ON(wlp->xmit_frame == NULL);
1836 result = wlp->xmit_frame(wlp, resp, src);
1837 if (result < 0) {
1838 dev_err(dev, "WLP: Unable to transmit response association "
1839 "message: %d\n", result);
1840 if (result == -ENXIO)
1841 dev_err(dev, "WLP: Is network interface up? \n");
1842
1843 dev_kfree_skb_any(resp);
1844 }
1845out:
1846 kfree_skb(frame_ctx->skb);
1847 kfree(frame_ctx);
1848 mutex_unlock(&wss->mutex);
1849 d_fnend(6, dev, "WLP: handle C1 frame. wlp = %p\n", wlp);
1850}
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860void wlp_handle_c3_frame(struct work_struct *ws)
1861{
1862 struct wlp_assoc_frame_ctx *frame_ctx = container_of(ws,
1863 struct wlp_assoc_frame_ctx,
1864 ws);
1865 struct wlp *wlp = frame_ctx->wlp;
1866 struct wlp_wss *wss = &wlp->wss;
1867 struct device *dev = &wlp->rc->uwb_dev.dev;
1868 struct sk_buff *skb = frame_ctx->skb;
1869 struct uwb_dev_addr *src = &frame_ctx->src;
1870 int result;
1871 char buf[WLP_WSS_UUID_STRSIZE];
1872 struct sk_buff *resp = NULL;
1873 struct wlp_uuid wssid;
1874 u8 tag;
1875 struct uwb_mac_addr virt_addr;
1876
1877
1878 d_fnstart(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
1879 wlp, skb);
1880 mutex_lock(&wss->mutex);
1881 result = wlp_parse_c3c4_frame(wlp, skb, &wssid, &tag, &virt_addr);
1882 if (result < 0) {
1883 dev_err(dev, "WLP: unable to obtain values from C3 frame.\n");
1884 goto out;
1885 }
1886 wlp_wss_uuid_print(buf, sizeof(buf), &wssid);
1887 d_printf(6, dev, "Received C3 frame with WSSID %s \n", buf);
1888 if (!memcmp(&wssid, &wss->wssid, sizeof(wssid))
1889 && wss->state >= WLP_WSS_STATE_ACTIVE) {
1890 d_printf(6, dev, "WSSID from C3 frame is known locally "
1891 "and is active\n");
1892 result = wlp_eda_update_node(&wlp->eda, src, wss,
1893 (void *) virt_addr.data, tag,
1894 WLP_WSS_CONNECTED);
1895 if (result < 0) {
1896 dev_err(dev, "WLP: Unable to update EDA cache "
1897 "with new connected neighbor information.\n");
1898 result = wlp_build_assoc_f0(wlp, &resp,
1899 WLP_ASSOC_ERROR_INT);
1900 if (result < 0) {
1901 dev_err(dev, "WLP: Unable to construct F0 "
1902 "message.\n");
1903 goto out;
1904 }
1905 } else {
1906 wss->state = WLP_WSS_STATE_CONNECTED;
1907
1908 result = wlp_build_assoc_c4(wlp, wss, &resp);
1909 if (result < 0) {
1910 dev_err(dev, "WLP: Unable to construct C4 "
1911 "message.\n");
1912 goto out;
1913 }
1914 }
1915 } else {
1916 d_printf(6, dev, "WSSID from C3 frame is not known locally "
1917 "or is not active\n");
1918
1919 result = wlp_build_assoc_f0(wlp, &resp, WLP_ASSOC_ERROR_INV);
1920 if (result < 0) {
1921 dev_err(dev, "WLP: Unable to construct F0 message.\n");
1922 goto out;
1923 }
1924 }
1925
1926 d_printf(6, dev, "Transmitting response (C4/F0) frame to %02x:%02x \n",
1927 src->data[1], src->data[0]);
1928 BUG_ON(wlp->xmit_frame == NULL);
1929 result = wlp->xmit_frame(wlp, resp, src);
1930 if (result < 0) {
1931 dev_err(dev, "WLP: Unable to transmit response association "
1932 "message: %d\n", result);
1933 if (result == -ENXIO)
1934 dev_err(dev, "WLP: Is network interface up? \n");
1935
1936 dev_kfree_skb_any(resp);
1937 }
1938out:
1939 kfree_skb(frame_ctx->skb);
1940 kfree(frame_ctx);
1941 mutex_unlock(&wss->mutex);
1942 d_fnend(6, dev, "WLP: handle C3 frame. wlp = %p, skb = %p\n",
1943 wlp, skb);
1944}
1945
1946