~ubuntu-branches/ubuntu/wily/bluez/wily

« back to all changes in this revision

Viewing changes to attrib/att.c

ImportĀ upstreamĀ versionĀ 4.81

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  BlueZ - Bluetooth protocol stack for Linux
 
4
 *
 
5
 *  Copyright (C) 2010  Nokia Corporation
 
6
 *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
 
7
 *
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  (at your option) any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program; if not, write to the Free Software
 
21
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
22
 *
 
23
 */
 
24
 
 
25
#include <errno.h>
 
26
#include <stdint.h>
 
27
#include <stdlib.h>
 
28
 
 
29
#include <bluetooth/bluetooth.h>
 
30
#include <bluetooth/sdp.h>
 
31
#include <bluetooth/sdp_lib.h>
 
32
 
 
33
#include <glib.h>
 
34
 
 
35
#include "att.h"
 
36
 
 
37
const char *att_ecode2str(uint8_t status)
 
38
{
 
39
        switch (status)  {
 
40
        case ATT_ECODE_INVALID_HANDLE:
 
41
                return "Invalid handle";
 
42
        case ATT_ECODE_READ_NOT_PERM:
 
43
                return "Atribute can't be read";
 
44
        case ATT_ECODE_WRITE_NOT_PERM:
 
45
                return "Attribute can't be written";
 
46
        case ATT_ECODE_INVALID_PDU:
 
47
                return "Attribute PDU was invalid";
 
48
        case ATT_ECODE_INSUFF_AUTHEN:
 
49
                return "Attribute requires authentication before read/write";
 
50
        case ATT_ECODE_REQ_NOT_SUPP:
 
51
                return "Server doesn't support the request received";
 
52
        case ATT_ECODE_INVALID_OFFSET:
 
53
                return "Offset past the end of the attribute";
 
54
        case ATT_ECODE_INSUFF_AUTHO:
 
55
                return "Attribute requires authorization before read/write";
 
56
        case ATT_ECODE_PREP_QUEUE_FULL:
 
57
                return "Too many prepare writes have been queued";
 
58
        case ATT_ECODE_ATTR_NOT_FOUND:
 
59
                return "No attribute found within the given range";
 
60
        case ATT_ECODE_ATTR_NOT_LONG:
 
61
                return "Attribute can't be read/written using Read Blob Req";
 
62
        case ATT_ECODE_INSUFF_ENCR_KEY_SIZE:
 
63
                return "Encryption Key Size is insufficient";
 
64
        case ATT_ECODE_INVAL_ATTR_VALUE_LEN:
 
65
                return "Attribute value length is invalid";
 
66
        case ATT_ECODE_UNLIKELY:
 
67
                return "Request attribute has encountered an unlikely error";
 
68
        case ATT_ECODE_INSUFF_ENC:
 
69
                return "Encryption required before read/write";
 
70
        case ATT_ECODE_UNSUPP_GRP_TYPE:
 
71
                return "Attribute type is not a supported grouping attribute";
 
72
        case ATT_ECODE_INSUFF_RESOURCES:
 
73
                return "Insufficient Resources to complete the request";
 
74
        case ATT_ECODE_IO:
 
75
                return "Internal application error: I/O";
 
76
        default:
 
77
                return "Unexpected error code";
 
78
        }
 
79
}
 
80
 
 
81
void att_data_list_free(struct att_data_list *list)
 
82
{
 
83
        int i;
 
84
 
 
85
        for (i = 0; i < list->num; i++)
 
86
                free(list->data[i]);
 
87
 
 
88
        free(list->data);
 
89
        free(list);
 
90
}
 
91
 
 
92
uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, uuid_t *uuid,
 
93
                                                        uint8_t *pdu, int len)
 
94
{
 
95
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
 
96
        uint16_t length;
 
97
 
 
98
        if (!uuid)
 
99
                return 0;
 
100
 
 
101
        if (uuid->type == SDP_UUID16)
 
102
                length = 2;
 
103
        else if (uuid->type == SDP_UUID128)
 
104
                length = 16;
 
105
        else
 
106
                return 0;
 
107
 
 
108
        if (len < min_len + length)
 
109
                return 0;
 
110
 
 
111
        pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
 
112
        att_put_u16(start, &pdu[1]);
 
113
        att_put_u16(end, &pdu[3]);
 
114
 
 
115
        if (uuid->type == SDP_UUID16)
 
116
                att_put_u16(uuid->value.uuid16, &pdu[5]);
 
117
        else
 
118
                memcpy(&pdu[5], &uuid->value.uuid128, length);
 
119
 
 
120
        return min_len + length;
 
121
}
 
122
 
 
123
uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
 
124
                                                uint16_t *end, uuid_t *uuid)
 
125
{
 
126
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
 
127
 
 
128
        if (pdu == NULL)
 
129
                return 0;
 
130
 
 
131
        if (start == NULL || end == NULL || uuid == NULL)
 
132
                return 0;
 
133
 
 
134
        if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
 
135
                return 0;
 
136
 
 
137
        if (len < min_len + 2)
 
138
                return 0;
 
139
 
 
140
        *start = att_get_u16(&pdu[1]);
 
141
        *end = att_get_u16(&pdu[3]);
 
142
        if (len == min_len + 2)
 
143
                sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
 
144
        else
 
145
                sdp_uuid128_create(uuid, &pdu[5]);
 
146
 
 
147
        return len;
 
148
}
 
149
 
 
150
uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
 
151
                                                                int len)
 
152
{
 
153
        int i;
 
154
        uint16_t w;
 
155
        uint8_t *ptr;
 
156
 
 
157
        if (list == NULL)
 
158
                return 0;
 
159
 
 
160
        if (len < list->len + 2)
 
161
                return 0;
 
162
 
 
163
        pdu[0] = ATT_OP_READ_BY_GROUP_RESP;
 
164
        pdu[1] = list->len;
 
165
 
 
166
        ptr = &pdu[2];
 
167
 
 
168
        for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
 
169
                memcpy(ptr, list->data[i], list->len);
 
170
                ptr += list->len;
 
171
                w += list->len;
 
172
        }
 
173
 
 
174
        return w;
 
175
}
 
176
 
 
177
struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
 
178
{
 
179
        struct att_data_list *list;
 
180
        const uint8_t *ptr;
 
181
        int i;
 
182
 
 
183
        if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP)
 
184
                return NULL;
 
185
 
 
186
        list = malloc(sizeof(struct att_data_list));
 
187
        list->len = pdu[1];
 
188
        list->num = (len - 2) / list->len;
 
189
 
 
190
        list->data = malloc(sizeof(uint8_t *) * list->num);
 
191
        ptr = &pdu[2];
 
192
 
 
193
        for (i = 0; i < list->num; i++) {
 
194
                list->data[i] = malloc(sizeof(uint8_t) * list->len);
 
195
                memcpy(list->data[i], ptr, list->len);
 
196
                ptr += list->len;
 
197
        }
 
198
 
 
199
        return list;
 
200
}
 
201
 
 
202
uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 
203
                        const uint8_t *value, int vlen, uint8_t *pdu, int len)
 
204
{
 
205
        uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) +
 
206
                                                        sizeof(uint16_t);
 
207
 
 
208
        if (pdu == NULL)
 
209
                return 0;
 
210
 
 
211
        if (!uuid)
 
212
                return 0;
 
213
 
 
214
        if (uuid->type != SDP_UUID16)
 
215
                return 0;
 
216
 
 
217
        if (len < min_len)
 
218
                return 0;
 
219
 
 
220
        if (vlen > len - min_len)
 
221
                vlen = len - min_len;
 
222
 
 
223
        pdu[0] = ATT_OP_FIND_BY_TYPE_REQ;
 
224
        att_put_u16(start, &pdu[1]);
 
225
        att_put_u16(end, &pdu[3]);
 
226
        att_put_u16(uuid->value.uuid16, &pdu[5]);
 
227
 
 
228
        if (vlen > 0) {
 
229
                memcpy(&pdu[7], value, vlen);
 
230
                return min_len + vlen;
 
231
        }
 
232
 
 
233
        return min_len;
 
234
}
 
235
 
 
236
uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 
237
                        uint16_t *end, uuid_t *uuid, uint8_t *value, int *vlen)
 
238
{
 
239
        int valuelen;
 
240
        uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
 
241
                                                sizeof(*end) + sizeof(uint16_t);
 
242
 
 
243
        if (pdu == NULL)
 
244
                return 0;
 
245
 
 
246
        if (len < min_len)
 
247
                return 0;
 
248
 
 
249
        if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
 
250
                return 0;
 
251
 
 
252
        /* First requested handle number */
 
253
        if (start)
 
254
                *start = att_get_u16(&pdu[1]);
 
255
 
 
256
        /* Last requested handle number */
 
257
        if (end)
 
258
                *end = att_get_u16(&pdu[3]);
 
259
 
 
260
        /* Always UUID16 */
 
261
        if (uuid)
 
262
                sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
 
263
 
 
264
        valuelen = len - min_len;
 
265
 
 
266
        /* Attribute value to find */
 
267
        if (valuelen > 0 && value)
 
268
                memcpy(value, pdu + min_len, valuelen);
 
269
 
 
270
        if (vlen)
 
271
                *vlen = valuelen;
 
272
 
 
273
        return len;
 
274
}
 
275
 
 
276
uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
 
277
{
 
278
        GSList *l;
 
279
        uint16_t offset;
 
280
 
 
281
        if (pdu == NULL || len < 5)
 
282
                return 0;
 
283
 
 
284
        pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
 
285
 
 
286
        for (l = matches, offset = 1; l && len >= (offset + 4);
 
287
                                        l = l->next, offset += 4) {
 
288
                struct att_range *range = l->data;
 
289
 
 
290
                att_put_u16(range->start, &pdu[offset]);
 
291
                att_put_u16(range->end, &pdu[offset + 2]);
 
292
        }
 
293
 
 
294
        return offset;
 
295
}
 
296
 
 
297
GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
 
298
{
 
299
        struct att_range *range;
 
300
        GSList *matches;
 
301
        int offset;
 
302
 
 
303
        if (pdu == NULL || len < 5)
 
304
                return NULL;
 
305
 
 
306
        if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
 
307
                return NULL;
 
308
 
 
309
        for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
 
310
                range = malloc(sizeof(struct att_range));
 
311
                range->start = att_get_u16(&pdu[offset]);
 
312
                range->end = att_get_u16(&pdu[offset + 2]);
 
313
 
 
314
                matches = g_slist_append(matches, range);
 
315
        }
 
316
 
 
317
        return matches;
 
318
}
 
319
 
 
320
uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, uuid_t *uuid,
 
321
                                                        uint8_t *pdu, int len)
 
322
{
 
323
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
 
324
        uint16_t length;
 
325
 
 
326
        if (!uuid)
 
327
                return 0;
 
328
 
 
329
        if (uuid->type == SDP_UUID16)
 
330
                length = 2;
 
331
        else if (uuid->type == SDP_UUID128)
 
332
                length = 16;
 
333
        else
 
334
                return 0;
 
335
 
 
336
        if (len < min_len + length)
 
337
                return 0;
 
338
 
 
339
        pdu[0] = ATT_OP_READ_BY_TYPE_REQ;
 
340
        att_put_u16(start, &pdu[1]);
 
341
        att_put_u16(end, &pdu[3]);
 
342
 
 
343
        if (uuid->type == SDP_UUID16)
 
344
                att_put_u16(uuid->value.uuid16, &pdu[5]);
 
345
        else
 
346
                memcpy(&pdu[5], &uuid->value.uuid128, length);
 
347
 
 
348
        return min_len + length;
 
349
}
 
350
 
 
351
uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
 
352
                                                uint16_t *end, uuid_t *uuid)
 
353
{
 
354
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
 
355
 
 
356
        if (pdu == NULL)
 
357
                return 0;
 
358
 
 
359
        if (start == NULL || end == NULL || uuid == NULL)
 
360
                return 0;
 
361
 
 
362
        if (len < min_len + 2)
 
363
                return 0;
 
364
 
 
365
        if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
 
366
                return 0;
 
367
 
 
368
        *start = att_get_u16(&pdu[1]);
 
369
        *end = att_get_u16(&pdu[3]);
 
370
 
 
371
        if (len == min_len + 2)
 
372
                sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
 
373
        else
 
374
                sdp_uuid128_create(uuid, &pdu[5]);
 
375
 
 
376
        return len;
 
377
}
 
378
 
 
379
uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len)
 
380
{
 
381
        uint8_t *ptr;
 
382
        int i, w, l;
 
383
 
 
384
        if (list == NULL)
 
385
                return 0;
 
386
 
 
387
        if (pdu == NULL)
 
388
                return 0;
 
389
 
 
390
        l = MIN(len - 2, list->len);
 
391
 
 
392
        pdu[0] = ATT_OP_READ_BY_TYPE_RESP;
 
393
        pdu[1] = l;
 
394
        ptr = &pdu[2];
 
395
 
 
396
        for (i = 0, w = 2; i < list->num && w + l <= len; i++) {
 
397
                memcpy(ptr, list->data[i], l);
 
398
                ptr += l;
 
399
                w += l;
 
400
        }
 
401
 
 
402
        return w;
 
403
}
 
404
 
 
405
struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
 
406
{
 
407
        struct att_data_list *list;
 
408
        const uint8_t *ptr;
 
409
        int i;
 
410
 
 
411
        if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
 
412
                return NULL;
 
413
 
 
414
        list = malloc(sizeof(struct att_data_list));
 
415
        list->len = pdu[1];
 
416
        list->num = (len - 2) / list->len;
 
417
 
 
418
        list->data = malloc(sizeof(uint8_t *) * list->num);
 
419
        ptr = &pdu[2];
 
420
 
 
421
        for (i = 0; i < list->num; i++) {
 
422
                list->data[i] = malloc(sizeof(uint8_t) * list->len);
 
423
                memcpy(list->data[i], ptr, list->len);
 
424
                ptr += list->len;
 
425
        }
 
426
 
 
427
        return list;
 
428
}
 
429
 
 
430
uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
 
431
                                                        uint8_t *pdu, int len)
 
432
{
 
433
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
434
 
 
435
        if (pdu == NULL)
 
436
                return 0;
 
437
 
 
438
        if (len < min_len)
 
439
                return 0;
 
440
 
 
441
        if (vlen > len - min_len)
 
442
                vlen = len - min_len;
 
443
 
 
444
        pdu[0] = ATT_OP_WRITE_CMD;
 
445
        att_put_u16(handle, &pdu[1]);
 
446
 
 
447
        if (vlen > 0) {
 
448
                memcpy(&pdu[3], value, vlen);
 
449
                return min_len + vlen;
 
450
        }
 
451
 
 
452
        return min_len;
 
453
}
 
454
 
 
455
uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
 
456
                                                uint8_t *value, int *vlen)
 
457
{
 
458
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
459
 
 
460
        if (pdu == NULL)
 
461
                return 0;
 
462
 
 
463
        if (value == NULL || vlen == NULL || handle == NULL)
 
464
                return 0;
 
465
 
 
466
        if (len < min_len)
 
467
                return 0;
 
468
 
 
469
        if (pdu[0] != ATT_OP_WRITE_CMD)
 
470
                return 0;
 
471
 
 
472
        *handle = att_get_u16(&pdu[1]);
 
473
        memcpy(value, pdu + min_len, len - min_len);
 
474
        *vlen = len - min_len;
 
475
 
 
476
        return len;
 
477
}
 
478
 
 
479
uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
 
480
                                                        uint8_t *pdu, int len)
 
481
{
 
482
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
483
 
 
484
        if (pdu == NULL)
 
485
                return 0;
 
486
 
 
487
        if (len < min_len)
 
488
                return 0;
 
489
 
 
490
        if (vlen > len - min_len)
 
491
                vlen = len - min_len;
 
492
 
 
493
        pdu[0] = ATT_OP_WRITE_REQ;
 
494
        att_put_u16(handle, &pdu[1]);
 
495
 
 
496
        if (vlen > 0) {
 
497
                memcpy(&pdu[3], value, vlen);
 
498
                return min_len + vlen;
 
499
        }
 
500
 
 
501
        return min_len;
 
502
}
 
503
 
 
504
uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
 
505
                                                uint8_t *value, int *vlen)
 
506
{
 
507
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
508
 
 
509
        if (pdu == NULL)
 
510
                return 0;
 
511
 
 
512
        if (value == NULL || vlen == NULL || handle == NULL)
 
513
                return 0;
 
514
 
 
515
        if (len < min_len)
 
516
                return 0;
 
517
 
 
518
        if (pdu[0] != ATT_OP_WRITE_REQ)
 
519
                return 0;
 
520
 
 
521
        *handle = att_get_u16(&pdu[1]);
 
522
        *vlen = len - min_len;
 
523
        if (*vlen > 0)
 
524
                memcpy(value, pdu + min_len, *vlen);
 
525
 
 
526
        return len;
 
527
}
 
528
 
 
529
uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
 
530
{
 
531
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
532
 
 
533
        if (pdu == NULL)
 
534
                return 0;
 
535
 
 
536
        if (len < min_len)
 
537
                return 0;
 
538
 
 
539
        pdu[0] = ATT_OP_READ_REQ;
 
540
        att_put_u16(handle, &pdu[1]);
 
541
 
 
542
        return min_len;
 
543
}
 
544
 
 
545
uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
 
546
{
 
547
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
548
 
 
549
        if (pdu == NULL)
 
550
                return 0;
 
551
 
 
552
        if (handle == NULL)
 
553
                return 0;
 
554
 
 
555
        if (len < min_len)
 
556
                return 0;
 
557
 
 
558
        if (pdu[0] != ATT_OP_READ_REQ)
 
559
                return 0;
 
560
 
 
561
        *handle = att_get_u16(&pdu[1]);
 
562
 
 
563
        return min_len;
 
564
}
 
565
 
 
566
uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
 
567
{
 
568
        if (pdu == NULL)
 
569
                return 0;
 
570
 
 
571
        /* If the attribute value length is longer than the allowed PDU size,
 
572
         * send only the octets that fit on the PDU. The remaining octets can
 
573
         * be requested using the Read Blob Request. */
 
574
        if (vlen > len - 1)
 
575
                vlen = len - 1;
 
576
 
 
577
        pdu[0] = ATT_OP_READ_RESP;
 
578
 
 
579
        memcpy(pdu + 1, value, vlen);
 
580
 
 
581
        return vlen + 1;
 
582
}
 
583
 
 
584
uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen)
 
585
{
 
586
        if (pdu == NULL)
 
587
                return 0;
 
588
 
 
589
        if (value == NULL || vlen == NULL)
 
590
                return 0;
 
591
 
 
592
        if (pdu[0] != ATT_OP_READ_RESP)
 
593
                return 0;
 
594
 
 
595
        memcpy(value, pdu + 1, len - 1);
 
596
 
 
597
        *vlen = len - 1;
 
598
 
 
599
        return len;
 
600
}
 
601
 
 
602
uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
 
603
                                                        uint8_t *pdu, int len)
 
604
{
 
605
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
 
606
                                                sizeof(handle) + sizeof(status);
 
607
        uint16_t u16;
 
608
 
 
609
        if (len < min_len)
 
610
                return 0;
 
611
 
 
612
        u16 = htobs(handle);
 
613
        pdu[0] = ATT_OP_ERROR;
 
614
        pdu[1] = opcode;
 
615
        memcpy(&pdu[2], &u16, sizeof(u16));
 
616
        pdu[4] = status;
 
617
 
 
618
        return min_len;
 
619
}
 
620
 
 
621
uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
 
622
{
 
623
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
 
624
 
 
625
        if (pdu == NULL)
 
626
                return 0;
 
627
 
 
628
        if (len < min_len)
 
629
                return 0;
 
630
 
 
631
        pdu[0] = ATT_OP_FIND_INFO_REQ;
 
632
        att_put_u16(start, &pdu[1]);
 
633
        att_put_u16(end, &pdu[3]);
 
634
 
 
635
        return min_len;
 
636
}
 
637
 
 
638
uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
 
639
                                                                uint16_t *end)
 
640
{
 
641
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
 
642
 
 
643
        if (pdu == NULL)
 
644
                return 0;
 
645
 
 
646
        if (len < min_len)
 
647
                return 0;
 
648
 
 
649
        if (start == NULL || end == NULL)
 
650
                return 0;
 
651
 
 
652
        if (pdu[0] != ATT_OP_FIND_INFO_REQ)
 
653
                return 0;
 
654
 
 
655
        *start = att_get_u16(&pdu[1]);
 
656
        *end = att_get_u16(&pdu[3]);
 
657
 
 
658
        return min_len;
 
659
}
 
660
 
 
661
uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
 
662
                                                        uint8_t *pdu, int len)
 
663
{
 
664
        uint8_t *ptr;
 
665
        int i, w;
 
666
 
 
667
        if (pdu == NULL)
 
668
                return 0;
 
669
 
 
670
        if (list == NULL)
 
671
                return 0;
 
672
 
 
673
        if (len < list->len + 2)
 
674
                return 0;
 
675
 
 
676
        pdu[0] = ATT_OP_FIND_INFO_RESP;
 
677
        pdu[1] = format;
 
678
        ptr = (void *) &pdu[2];
 
679
 
 
680
        for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
 
681
                memcpy(ptr, list->data[i], list->len);
 
682
                ptr += list->len;
 
683
                w += list->len;
 
684
        }
 
685
 
 
686
        return w;
 
687
}
 
688
 
 
689
struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
 
690
                                                        uint8_t *format)
 
691
{
 
692
        struct att_data_list *list;
 
693
        uint8_t *ptr;
 
694
        int i;
 
695
 
 
696
        if (pdu == NULL)
 
697
                return 0;
 
698
 
 
699
        if (format == NULL)
 
700
                return 0;
 
701
 
 
702
        if (pdu[0] != ATT_OP_FIND_INFO_RESP)
 
703
                return 0;
 
704
 
 
705
        *format = pdu[1];
 
706
 
 
707
        list = malloc(sizeof(struct att_data_list));
 
708
 
 
709
        list->len = sizeof(pdu[0]) + sizeof(*format);
 
710
        if (*format == 0x01)
 
711
                list->len += 2;
 
712
        else if (*format == 0x02)
 
713
                list->len += 16;
 
714
 
 
715
        list->num = (len - 2) / list->len;
 
716
        list->data = malloc(sizeof(uint8_t *) * list->num);
 
717
 
 
718
        ptr = (void *) &pdu[2];
 
719
 
 
720
        for (i = 0; i < list->num; i++) {
 
721
                list->data[i] = malloc(list->len);
 
722
                memcpy(list->data[i], ptr, list->len);
 
723
                ptr += list->len;
 
724
        }
 
725
 
 
726
        return list;
 
727
}
 
728
 
 
729
uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len)
 
730
{
 
731
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
732
 
 
733
        if (pdu == NULL)
 
734
                return 0;
 
735
 
 
736
        if (len < (a->len + min_len))
 
737
                return 0;
 
738
 
 
739
        pdu[0] = ATT_OP_HANDLE_NOTIFY;
 
740
        att_put_u16(a->handle, &pdu[1]);
 
741
        memcpy(&pdu[3], a->data, a->len);
 
742
 
 
743
        return a->len + min_len;
 
744
}
 
745
 
 
746
uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len)
 
747
{
 
748
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
749
 
 
750
        if (pdu == NULL)
 
751
                return 0;
 
752
 
 
753
        if (len < (a->len + min_len))
 
754
                return 0;
 
755
 
 
756
        pdu[0] = ATT_OP_HANDLE_IND;
 
757
        att_put_u16(a->handle, &pdu[1]);
 
758
        memcpy(&pdu[3], a->data, a->len);
 
759
 
 
760
        return a->len + min_len;
 
761
}
 
762
 
 
763
struct attribute *dec_indication(const uint8_t *pdu, int len)
 
764
{
 
765
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
766
 
 
767
        struct attribute *a;
 
768
 
 
769
        if (pdu == NULL)
 
770
                return NULL;
 
771
 
 
772
        if (pdu[0] != ATT_OP_HANDLE_IND)
 
773
                return NULL;
 
774
 
 
775
        if (len < min_len)
 
776
                return NULL;
 
777
 
 
778
        a = malloc(sizeof(struct attribute) + len - min_len);
 
779
        if (a == NULL)
 
780
                return NULL;
 
781
 
 
782
        a->len = len - min_len;
 
783
 
 
784
        a->handle = att_get_u16(&pdu[1]);
 
785
        memcpy(a->data, &pdu[3], a->len);
 
786
 
 
787
        return a;
 
788
}
 
789
 
 
790
uint16_t enc_confirmation(uint8_t *pdu, int len)
 
791
{
 
792
        const uint16_t min_len = sizeof(pdu[0]);
 
793
 
 
794
        if (pdu == NULL)
 
795
                return 0;
 
796
 
 
797
        if (len < min_len)
 
798
                return 0;
 
799
 
 
800
        pdu[0] = ATT_OP_HANDLE_CNF;
 
801
 
 
802
        return min_len;
 
803
}
 
804
 
 
805
uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
 
806
{
 
807
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
 
808
 
 
809
        if (pdu == NULL)
 
810
                return 0;
 
811
 
 
812
        if (len < min_len)
 
813
                return 0;
 
814
 
 
815
        pdu[0] = ATT_OP_MTU_REQ;
 
816
        att_put_u16(mtu, &pdu[1]);
 
817
 
 
818
        return min_len;
 
819
}
 
820
 
 
821
uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
 
822
{
 
823
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
 
824
 
 
825
        if (pdu == NULL)
 
826
                return 0;
 
827
 
 
828
        if (mtu == NULL)
 
829
                return 0;
 
830
 
 
831
        if (len < min_len)
 
832
                return 0;
 
833
 
 
834
        if (pdu[0] != ATT_OP_MTU_REQ)
 
835
                return 0;
 
836
 
 
837
        *mtu = att_get_u16(&pdu[1]);
 
838
 
 
839
        return min_len;
 
840
}
 
841
 
 
842
uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
 
843
{
 
844
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
 
845
 
 
846
        if (pdu == NULL)
 
847
                return 0;
 
848
 
 
849
        if (len < min_len)
 
850
                return 0;
 
851
 
 
852
        pdu[0] = ATT_OP_MTU_RESP;
 
853
        att_put_u16(mtu, &pdu[1]);
 
854
 
 
855
        return min_len;
 
856
}
 
857
 
 
858
uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
 
859
{
 
860
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
 
861
 
 
862
        if (pdu == NULL)
 
863
                return 0;
 
864
 
 
865
        if (mtu == NULL)
 
866
                return 0;
 
867
 
 
868
        if (len < min_len)
 
869
                return 0;
 
870
 
 
871
        if (pdu[0] != ATT_OP_MTU_RESP)
 
872
                return 0;
 
873
 
 
874
        *mtu = att_get_u16(&pdu[1]);
 
875
 
 
876
        return min_len;
 
877
}