Coverage Report

Created: 2025-01-28 06:43

/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
298
#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
140
{
221
140
  GObexPacket *pkt;
222
223
140
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
224
225
140
  pkt = g_new0(GObexPacket, 1);
226
227
140
  pkt->opcode = opcode;
228
140
  pkt->final = final;
229
140
  pkt->headers = g_obex_header_create_list(first_hdr_id, args,
230
140
                &pkt->hlen);
231
140
  pkt->data_policy = G_OBEX_DATA_COPY;
232
233
140
  return pkt;
234
140
}
235
236
GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
237
            guint first_hdr_id, ...)
238
140
{
239
140
  GObexPacket *pkt;
240
140
  va_list args;
241
242
140
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
243
244
140
  va_start(args, first_hdr_id);
245
140
  pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
246
140
  va_end(args);
247
248
140
  return pkt;
249
140
}
250
251
static void header_free(void *data, void *user_data)
252
4.90k
{
253
4.90k
  g_obex_header_free(data);
254
4.90k
}
255
256
void g_obex_packet_free(GObexPacket *pkt)
257
140
{
258
140
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
259
260
140
  switch (pkt->data_policy) {
261
0
  case G_OBEX_DATA_INHERIT:
262
140
  case G_OBEX_DATA_COPY:
263
140
    free(pkt->data.buf);
264
140
    break;
265
0
  case G_OBEX_DATA_REF:
266
0
    break;
267
140
  }
268
269
140
  g_slist_foreach(pkt->headers, header_free, NULL);
270
140
  g_slist_free(pkt->headers);
271
140
  g_free(pkt);
272
140
}
273
274
static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
275
            GObexDataPolicy data_policy,
276
            GError **err)
277
140
{
278
140
  const guint8 *buf = data;
279
280
140
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
281
282
5.04k
  while (len > 0) {
283
4.98k
    GObexHeader *header;
284
4.98k
    gsize parsed;
285
286
4.98k
    header = g_obex_header_decode(buf, len, data_policy, &parsed,
287
4.98k
                  err);
288
4.98k
    if (header == NULL)
289
76
      return FALSE;
290
291
4.90k
    pkt->headers = g_slist_append(pkt->headers, header);
292
4.90k
    pkt->hlen += parsed;
293
294
4.90k
    len -= parsed;
295
4.90k
    buf += parsed;
296
4.90k
  }
297
298
64
  return TRUE;
299
140
}
300
301
static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
302
328
{
303
328
  memcpy(to, from, count);
304
328
  return (from + count);
305
328
}
306
307
GObexPacket *g_obex_packet_decode(const void *data, gsize len,
308
            gsize header_offset,
309
            GObexDataPolicy data_policy,
310
            GError **err)
311
164
{
312
164
  const guint8 *buf = data;
313
164
  guint16 packet_len;
314
164
  guint8 opcode;
315
164
  GObexPacket *pkt;
316
164
  gboolean final;
317
318
164
  g_obex_debug(G_OBEX_DEBUG_PACKET, "");
319
320
164
  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
164
  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
164
  buf = get_bytes(&opcode, buf, sizeof(opcode));
339
164
  buf = get_bytes(&packet_len, buf, sizeof(packet_len));
340
341
164
  packet_len = g_ntohs(packet_len);
342
164
  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
140
  final = (opcode & FINAL_BIT) ? TRUE : FALSE;
353
140
  opcode &= ~FINAL_BIT;
354
355
140
  pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
356
357
140
  if (header_offset == 0)
358
140
    goto headers;
359
360
0
  g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
361
0
  buf += header_offset;
362
363
140
headers:
364
140
  if (!parse_headers(pkt, buf, len - (3 + header_offset),
365
140
              data_policy, err))
366
76
    goto failed;
367
368
64
  return pkt;
369
370
76
failed:
371
76
  g_obex_packet_free(pkt);
372
76
  return NULL;
373
140
}
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
64
{
402
64
  gssize ret;
403
64
  gsize count;
404
64
  guint16 u16;
405
64
  GSList *l;
406
407
64
  g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
408
409
64
  if (3 + pkt->data_len + pkt->hlen > len)
410
16
    return -ENOBUFS;
411
412
48
  buf[0] = pkt->opcode;
413
48
  if (pkt->final)
414
18
    buf[0] |= FINAL_BIT;
415
416
48
  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
48
  count = 3 + pkt->data_len;
424
425
601
  for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
426
553
    GObexHeader *hdr = l->data;
427
428
553
    if (count >= len)
429
0
      return -ENOBUFS;
430
431
553
    ret = g_obex_header_encode(hdr, buf + count, len - count);
432
553
    if (ret < 0)
433
0
      return ret;
434
435
553
    count += ret;
436
553
  }
437
438
48
  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
48
  u16 = g_htons(count);
452
48
  memcpy(&buf[1], &u16, sizeof(u16));
453
454
48
  return count;
455
48
}