Coverage Report

Created: 2024-05-20 06:10

/src/bluez/gobex/gobex-packet.c
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 *
4
 *  OBEX library with GLib integration
5
 *
6
 *  Copyright (C) 2011  Intel Corporation. All rights reserved.
7
 *
8
 */
9
10
#ifdef HAVE_CONFIG_H
11
#include <config.h>
12
#endif
13
14
#include <string.h>
15
#include <errno.h>
16
17
#include "gobex-defs.h"
18
#include "gobex-packet.h"
19
#include "gobex-debug.h"
20
#include "src/shared/util.h"
21
22
255
#define FINAL_BIT 0x80
23
24
struct _GObexPacket {
25
  guint8 opcode;
26
  gboolean final;
27
28
  GObexDataPolicy data_policy;
29
30
  union {
31
    void *buf;    /* Non-header data */
32
    const void *buf_ref;  /* Reference to non-header data */
33
  } data;
34
  gsize data_len;
35
36
  gsize hlen;   /* Length of all encoded headers */
37
  GSList *headers;
38
39
  GObexDataProducer get_body;
40
  gpointer get_body_data;
41
};
42
43
GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
44
0
{
45
0
  GSList *l;
46
47
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
48
49
0
  for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
50
0
    GObexHeader *hdr = l->data;
51
52
0
    if (g_obex_header_get_id(hdr) == id)
53
0
      return hdr;
54
0
  }
55
56
0
  return NULL;
57
0
}
58
59
GObexHeader *g_obex_packet_get_body(GObexPacket *pkt)
60
0
{
61
0
  GObexHeader *body;
62
63
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
64
65
0
  body = g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY);
66
0
  if (body != NULL)
67
0
    return body;
68
69
0
  return g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY_END);
70
0
}
71
72
guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
73
0
{
74
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
75
76
0
  if (final)
77
0
    *final = pkt->final;
78
79
0
  return pkt->opcode;
80
0
}
81
82
gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header)
83
0
{
84
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
85
86
0
  pkt->headers = g_slist_prepend(pkt->headers, header);
87
0
  pkt->hlen += g_obex_header_get_length(header);
88
89
0
  return TRUE;
90
0
}
91
92
gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
93
0
{
94
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
95
96
0
  pkt->headers = g_slist_append(pkt->headers, header);
97
0
  pkt->hlen += g_obex_header_get_length(header);
98
99
0
  return TRUE;
100
0
}
101
102
gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
103
              gpointer user_data)
104
0
{
105
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
106
107
0
  if (pkt->get_body != NULL)
108
0
    return FALSE;
109
110
0
  pkt->get_body = func;
111
0
  pkt->get_body_data = user_data;
112
113
0
  return TRUE;
114
0
}
115
116
gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
117
              const char *str)
118
0
{
119
0
  GObexHeader *hdr;
120
121
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
122
123
0
  hdr = g_obex_header_new_unicode(id, str);
124
0
  if (hdr == NULL)
125
0
    return FALSE;
126
127
0
  return g_obex_packet_add_header(pkt, hdr);
128
0
}
129
130
gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
131
            const void *data, gsize len)
132
0
{
133
0
  GObexHeader *hdr;
134
135
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
136
137
0
  hdr = g_obex_header_new_bytes(id, data, len);
138
0
  if (hdr == NULL)
139
0
    return FALSE;
140
141
0
  return g_obex_packet_add_header(pkt, hdr);
142
0
}
143
144
gboolean g_obex_packet_add_uint8(GObexPacket *pkt, guint8 id, guint8 val)
145
0
{
146
0
  GObexHeader *hdr;
147
148
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
149
150
0
  hdr = g_obex_header_new_uint8(id, val);
151
0
  if (hdr == NULL)
152
0
    return FALSE;
153
154
0
  return g_obex_packet_add_header(pkt, hdr);
155
0
}
156
157
gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val)
158
0
{
159
0
  GObexHeader *hdr;
160
161
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
162
163
0
  hdr = g_obex_header_new_uint32(id, val);
164
0
  if (hdr == NULL)
165
0
    return FALSE;
166
167
0
  return g_obex_packet_add_header(pkt, hdr);
168
0
}
169
170
const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len)
171
0
{
172
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
173
174
0
  if (pkt->data_len == 0) {
175
0
    *len = 0;
176
0
    return NULL;
177
0
  }
178
179
0
  *len = pkt->data_len;
180
181
0
  switch (pkt->data_policy) {
182
0
  case G_OBEX_DATA_INHERIT:
183
0
  case G_OBEX_DATA_COPY:
184
0
    return pkt->data.buf;
185
0
  case G_OBEX_DATA_REF:
186
0
    return pkt->data.buf_ref;
187
0
  }
188
189
0
  g_assert_not_reached();
190
0
}
191
192
gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
193
            GObexDataPolicy data_policy)
194
0
{
195
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
196
197
0
  if (pkt->data.buf || pkt->data.buf_ref)
198
0
    return FALSE;
199
200
0
  pkt->data_policy = data_policy;
201
0
  pkt->data_len = len;
202
203
0
  switch (data_policy) {
204
0
  case G_OBEX_DATA_COPY:
205
0
    pkt->data.buf = util_memdup(data, len);
206
0
    break;
207
0
  case G_OBEX_DATA_REF:
208
0
    pkt->data.buf_ref = data;
209
0
    break;
210
0
  case G_OBEX_DATA_INHERIT:
211
0
    pkt->data.buf = (void *) data;
212
0
    break;
213
0
  }
214
215
0
  return TRUE;
216
0
}
217
218
GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
219
          guint first_hdr_id, va_list args)
220
118
{
221
118
  GObexPacket *pkt;
222
223
118
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
224
225
118
  pkt = g_new0(GObexPacket, 1);
226
227
118
  pkt->opcode = opcode;
228
118
  pkt->final = final;
229
118
  pkt->headers = g_obex_header_create_list(first_hdr_id, args,
230
118
                &pkt->hlen);
231
118
  pkt->data_policy = G_OBEX_DATA_COPY;
232
233
118
  return pkt;
234
118
}
235
236
GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
237
            guint first_hdr_id, ...)
238
118
{
239
118
  GObexPacket *pkt;
240
118
  va_list args;
241
242
118
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
243
244
118
  va_start(args, first_hdr_id);
245
118
  pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
246
118
  va_end(args);
247
248
118
  return pkt;
249
118
}
250
251
static void header_free(void *data, void *user_data)
252
2.33k
{
253
2.33k
  g_obex_header_free(data);
254
2.33k
}
255
256
void g_obex_packet_free(GObexPacket *pkt)
257
118
{
258
118
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
259
260
118
  switch (pkt->data_policy) {
261
0
  case G_OBEX_DATA_INHERIT:
262
118
  case G_OBEX_DATA_COPY:
263
118
    free(pkt->data.buf);
264
118
    break;
265
0
  case G_OBEX_DATA_REF:
266
0
    break;
267
118
  }
268
269
118
  g_slist_foreach(pkt->headers, header_free, NULL);
270
118
  g_slist_free(pkt->headers);
271
118
  g_free(pkt);
272
118
}
273
274
static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
275
            GObexDataPolicy data_policy,
276
            GError **err)
277
118
{
278
118
  const guint8 *buf = data;
279
280
118
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
281
282
2.45k
  while (len > 0) {
283
2.39k
    GObexHeader *header;
284
2.39k
    gsize parsed;
285
286
2.39k
    header = g_obex_header_decode(buf, len, data_policy, &parsed,
287
2.39k
                  err);
288
2.39k
    if (header == NULL)
289
57
      return FALSE;
290
291
2.33k
    pkt->headers = g_slist_append(pkt->headers, header);
292
2.33k
    pkt->hlen += parsed;
293
294
2.33k
    len -= parsed;
295
2.33k
    buf += parsed;
296
2.33k
  }
297
298
61
  return TRUE;
299
118
}
300
301
static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
302
284
{
303
284
  memcpy(to, from, count);
304
284
  return (from + count);
305
284
}
306
307
GObexPacket *g_obex_packet_decode(const void *data, gsize len,
308
            gsize header_offset,
309
            GObexDataPolicy data_policy,
310
            GError **err)
311
142
{
312
142
  const guint8 *buf = data;
313
142
  guint16 packet_len;
314
142
  guint8 opcode;
315
142
  GObexPacket *pkt;
316
142
  gboolean final;
317
318
142
  g_obex_debug(G_OBEX_DEBUG_PACKET, "");
319
320
142
  if (data_policy == G_OBEX_DATA_INHERIT) {
321
0
    if (!err)
322
0
      return NULL;
323
0
    g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
324
0
              "Invalid data policy");
325
0
    g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
326
0
    return NULL;
327
0
  }
328
329
142
  if (len < 3 + header_offset) {
330
0
    if (!err)
331
0
      return NULL;
332
0
    g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
333
0
          "Not enough data to decode packet");
334
0
    g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
335
0
    return NULL;
336
0
  }
337
338
142
  buf = get_bytes(&opcode, buf, sizeof(opcode));
339
142
  buf = get_bytes(&packet_len, buf, sizeof(packet_len));
340
341
142
  packet_len = g_ntohs(packet_len);
342
142
  if (packet_len != len) {
343
24
    if (!err)
344
0
      return NULL;
345
24
    g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
346
24
        "Incorrect packet length (%u != %zu)",
347
24
        packet_len, len);
348
24
    g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
349
24
    return NULL;
350
24
  }
351
352
118
  final = (opcode & FINAL_BIT) ? TRUE : FALSE;
353
118
  opcode &= ~FINAL_BIT;
354
355
118
  pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
356
357
118
  if (header_offset == 0)
358
118
    goto headers;
359
360
0
  g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
361
0
  buf += header_offset;
362
363
118
headers:
364
118
  if (!parse_headers(pkt, buf, len - (3 + header_offset),
365
118
              data_policy, err))
366
57
    goto failed;
367
368
61
  return pkt;
369
370
57
failed:
371
57
  g_obex_packet_free(pkt);
372
57
  return NULL;
373
118
}
374
375
static gssize get_body(GObexPacket *pkt, guint8 *buf, gsize len)
376
0
{
377
0
  guint16 u16;
378
0
  gssize ret;
379
380
0
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
381
382
0
  if (len < 3)
383
0
    return -ENOBUFS;
384
385
0
  ret = pkt->get_body(buf + 3, len - 3, pkt->get_body_data);
386
0
  if (ret < 0)
387
0
    return ret;
388
389
0
  if (ret > 0)
390
0
    buf[0] = G_OBEX_HDR_BODY;
391
0
  else
392
0
    buf[0] = G_OBEX_HDR_BODY_END;
393
394
0
  u16 = g_htons(ret + 3);
395
0
  memcpy(&buf[1], &u16, sizeof(u16));
396
397
0
  return ret;
398
0
}
399
400
gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len)
401
61
{
402
61
  gssize ret;
403
61
  gsize count;
404
61
  guint16 u16;
405
61
  GSList *l;
406
407
61
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
408
409
61
  if (3 + pkt->data_len + pkt->hlen > len)
410
16
    return -ENOBUFS;
411
412
45
  buf[0] = pkt->opcode;
413
45
  if (pkt->final)
414
19
    buf[0] |= FINAL_BIT;
415
416
45
  if (pkt->data_len > 0) {
417
0
    if (pkt->data_policy == G_OBEX_DATA_REF)
418
0
      memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
419
0
    else
420
0
      memcpy(&buf[3], pkt->data.buf, pkt->data_len);
421
0
  }
422
423
45
  count = 3 + pkt->data_len;
424
425
564
  for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
426
519
    GObexHeader *hdr = l->data;
427
428
519
    if (count >= len)
429
0
      return -ENOBUFS;
430
431
519
    ret = g_obex_header_encode(hdr, buf + count, len - count);
432
519
    if (ret < 0)
433
0
      return ret;
434
435
519
    count += ret;
436
519
  }
437
438
45
  if (pkt->get_body) {
439
0
    ret = get_body(pkt, buf + count, len - count);
440
0
    if (ret < 0)
441
0
      return ret;
442
0
    if (ret == 0) {
443
0
      if (pkt->opcode == G_OBEX_RSP_CONTINUE)
444
0
        buf[0] = G_OBEX_RSP_SUCCESS;
445
0
      buf[0] |= FINAL_BIT;
446
0
    }
447
448
0
    count += ret + 3;
449
0
  }
450
451
45
  u16 = g_htons(count);
452
45
  memcpy(&buf[1], &u16, sizeof(u16));
453
454
45
  return count;
455
45
}