• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stdint.h>
26 #include <string.h>
27 #include <glib.h>
28 
29 #include <stdio.h>
30 
31 #include <bluetooth/bluetooth.h>
32 #include <bluetooth/uuid.h>
33 
34 #include "att.h"
35 #include "btio.h"
36 #include "gattrib.h"
37 
38 #define GATT_TIMEOUT 30
39 
40 struct _GAttrib {
41 	GIOChannel *io;
42 	gint refs;
43 	uint8_t *buf;
44 	int buflen;
45 	guint read_watch;
46 	guint write_watch;
47 	guint timeout_watch;
48 	GQueue *queue;
49 	GSList *events;
50 	guint next_cmd_id;
51 	guint next_evt_id;
52 	GDestroyNotify destroy;
53 	GAttribDisconnectFunc disconnect;
54 	gpointer destroy_user_data;
55 	gpointer disc_user_data;
56 };
57 
58 struct command {
59 	guint id;
60 	guint8 opcode;
61 	guint8 *pdu;
62 	guint16 len;
63 	guint8 expected;
64 	gboolean sent;
65 	GAttribResultFunc func;
66 	gpointer user_data;
67 	GDestroyNotify notify;
68 };
69 
70 struct event {
71 	guint id;
72 	guint8 expected;
73 	GAttribNotifyFunc func;
74 	gpointer user_data;
75 	GDestroyNotify notify;
76 };
77 
opcode2expected(guint8 opcode)78 static guint8 opcode2expected(guint8 opcode)
79 {
80 	switch (opcode) {
81 	case ATT_OP_MTU_REQ:
82 		return ATT_OP_MTU_RESP;
83 
84 	case ATT_OP_FIND_INFO_REQ:
85 		return ATT_OP_FIND_INFO_RESP;
86 
87 	case ATT_OP_FIND_BY_TYPE_REQ:
88 		return ATT_OP_FIND_BY_TYPE_RESP;
89 
90 	case ATT_OP_READ_BY_TYPE_REQ:
91 		return ATT_OP_READ_BY_TYPE_RESP;
92 
93 	case ATT_OP_READ_REQ:
94 		return ATT_OP_READ_RESP;
95 
96 	case ATT_OP_READ_BLOB_REQ:
97 		return ATT_OP_READ_BLOB_RESP;
98 
99 	case ATT_OP_READ_MULTI_REQ:
100 		return ATT_OP_READ_MULTI_RESP;
101 
102 	case ATT_OP_READ_BY_GROUP_REQ:
103 		return ATT_OP_READ_BY_GROUP_RESP;
104 
105 	case ATT_OP_WRITE_REQ:
106 		return ATT_OP_WRITE_RESP;
107 
108 	case ATT_OP_PREP_WRITE_REQ:
109 		return ATT_OP_PREP_WRITE_RESP;
110 
111 	case ATT_OP_EXEC_WRITE_REQ:
112 		return ATT_OP_EXEC_WRITE_RESP;
113 
114 	case ATT_OP_HANDLE_IND:
115 		return ATT_OP_HANDLE_CNF;
116 	}
117 
118 	return 0;
119 }
120 
is_response(guint8 opcode)121 static gboolean is_response(guint8 opcode)
122 {
123 	switch (opcode) {
124 	case ATT_OP_ERROR:
125 	case ATT_OP_MTU_RESP:
126 	case ATT_OP_FIND_INFO_RESP:
127 	case ATT_OP_FIND_BY_TYPE_RESP:
128 	case ATT_OP_READ_BY_TYPE_RESP:
129 	case ATT_OP_READ_RESP:
130 	case ATT_OP_READ_BLOB_RESP:
131 	case ATT_OP_READ_MULTI_RESP:
132 	case ATT_OP_READ_BY_GROUP_RESP:
133 	case ATT_OP_WRITE_RESP:
134 	case ATT_OP_PREP_WRITE_RESP:
135 	case ATT_OP_EXEC_WRITE_RESP:
136 	case ATT_OP_HANDLE_CNF:
137 		return TRUE;
138 	}
139 
140 	return FALSE;
141 }
142 
g_attrib_ref(GAttrib * attrib)143 GAttrib *g_attrib_ref(GAttrib *attrib)
144 {
145 	if (!attrib)
146 		return NULL;
147 
148 	g_atomic_int_inc(&attrib->refs);
149 
150 	return attrib;
151 }
152 
command_destroy(struct command * cmd)153 static void command_destroy(struct command *cmd)
154 {
155 	if (cmd->notify)
156 		cmd->notify(cmd->user_data);
157 
158 	g_free(cmd->pdu);
159 	g_free(cmd);
160 }
161 
event_destroy(struct event * evt)162 static void event_destroy(struct event *evt)
163 {
164 	if (evt->notify)
165 		evt->notify(evt->user_data);
166 
167 	g_free(evt);
168 }
169 
attrib_destroy(GAttrib * attrib)170 static void attrib_destroy(GAttrib *attrib)
171 {
172 	GSList *l;
173 	struct command *c;
174 
175 	while ((c = g_queue_pop_head(attrib->queue)))
176 		command_destroy(c);
177 
178 	g_queue_free(attrib->queue);
179 	attrib->queue = NULL;
180 
181 	for (l = attrib->events; l; l = l->next)
182 		event_destroy(l->data);
183 
184 	g_slist_free(attrib->events);
185 	attrib->events = NULL;
186 
187 	if (attrib->timeout_watch > 0)
188 		g_source_remove(attrib->timeout_watch);
189 
190 	if (attrib->write_watch > 0)
191 		g_source_remove(attrib->write_watch);
192 
193 	if (attrib->read_watch > 0) {
194 		g_source_remove(attrib->read_watch);
195 		g_io_channel_unref(attrib->io);
196 	}
197 
198 	g_free(attrib->buf);
199 
200 	if (attrib->destroy)
201 		attrib->destroy(attrib->destroy_user_data);
202 
203 	g_free(attrib);
204 }
205 
g_attrib_unref(GAttrib * attrib)206 void g_attrib_unref(GAttrib *attrib)
207 {
208 	if (!attrib)
209 		return;
210 
211 	if (g_atomic_int_dec_and_test(&attrib->refs) == FALSE)
212 		return;
213 
214 	attrib_destroy(attrib);
215 }
216 
g_attrib_get_channel(GAttrib * attrib)217 GIOChannel *g_attrib_get_channel(GAttrib *attrib)
218 {
219 	if (!attrib)
220 		return NULL;
221 
222 	return attrib->io;
223 }
224 
g_attrib_set_disconnect_function(GAttrib * attrib,GAttribDisconnectFunc disconnect,gpointer user_data)225 gboolean g_attrib_set_disconnect_function(GAttrib *attrib,
226 		GAttribDisconnectFunc disconnect, gpointer user_data)
227 {
228 	if (attrib == NULL)
229 		return FALSE;
230 
231 	attrib->disconnect = disconnect;
232 	attrib->disc_user_data = user_data;
233 
234 	return TRUE;
235 }
236 
g_attrib_set_destroy_function(GAttrib * attrib,GDestroyNotify destroy,gpointer user_data)237 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
238 		GDestroyNotify destroy, gpointer user_data)
239 {
240 	if (attrib == NULL)
241 		return FALSE;
242 
243 	attrib->destroy = destroy;
244 	attrib->destroy_user_data = user_data;
245 
246 	return TRUE;
247 }
248 
disconnect_timeout(gpointer data)249 static gboolean disconnect_timeout(gpointer data)
250 {
251 	struct _GAttrib *attrib = data;
252 
253 	attrib_destroy(attrib);
254 
255 	return FALSE;
256 }
257 
can_write_data(GIOChannel * io,GIOCondition cond,gpointer data)258 static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
259 								gpointer data)
260 {
261 	struct _GAttrib *attrib = data;
262 	struct command *cmd;
263 	GError *gerr = NULL;
264 	gsize len;
265 	GIOStatus iostat;
266 
267 	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
268 		if (attrib->disconnect)
269 			attrib->disconnect(attrib->disc_user_data);
270 
271 		return FALSE;
272 	}
273 
274 	cmd = g_queue_peek_head(attrib->queue);
275 	if (cmd == NULL)
276 		return FALSE;
277 
278 	iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
279 								&len, &gerr);
280 	if (iostat != G_IO_STATUS_NORMAL)
281 		return FALSE;
282 
283 	if (cmd->expected == 0) {
284 		g_queue_pop_head(attrib->queue);
285 		command_destroy(cmd);
286 
287 		return TRUE;
288 	}
289 
290 	cmd->sent = TRUE;
291 
292 	if (attrib->timeout_watch == 0)
293 		attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
294 						disconnect_timeout, attrib);
295 
296 	return FALSE;
297 }
298 
destroy_sender(gpointer data)299 static void destroy_sender(gpointer data)
300 {
301 	struct _GAttrib *attrib = data;
302 
303 	attrib->write_watch = 0;
304 }
305 
wake_up_sender(struct _GAttrib * attrib)306 static void wake_up_sender(struct _GAttrib *attrib)
307 {
308 	if (attrib->write_watch == 0)
309 		attrib->write_watch = g_io_add_watch_full(attrib->io,
310 			G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data,
311 			attrib, destroy_sender);
312 }
313 
received_data(GIOChannel * io,GIOCondition cond,gpointer data)314 static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
315 {
316 	struct _GAttrib *attrib = data;
317 	struct command *cmd = NULL;
318 	GSList *l;
319 	uint8_t buf[512], status;
320 	gsize len;
321 	GIOStatus iostat;
322 	gboolean qempty;
323 
324 	if (attrib->timeout_watch > 0) {
325 		g_source_remove(attrib->timeout_watch);
326 		attrib->timeout_watch = 0;
327 	}
328 
329 	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
330 		attrib->read_watch = 0;
331 		if (attrib->disconnect)
332 			attrib->disconnect(attrib->disc_user_data);
333 		return FALSE;
334 	}
335 
336 	memset(buf, 0, sizeof(buf));
337 
338 	iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf),
339 								&len, NULL);
340 	if (iostat != G_IO_STATUS_NORMAL) {
341 		status = ATT_ECODE_IO;
342 		goto done;
343 	}
344 
345 	for (l = attrib->events; l; l = l->next) {
346 		struct event *evt = l->data;
347 
348 		if (evt->expected == buf[0] ||
349 					evt->expected == GATTRIB_ALL_EVENTS)
350 			evt->func(buf, len, evt->user_data);
351 	}
352 
353 	if (is_response(buf[0]) == FALSE)
354 		return TRUE;
355 
356 	cmd = g_queue_pop_head(attrib->queue);
357 	if (cmd == NULL) {
358 		/* Keep the watch if we have events to report */
359 		return attrib->events != NULL;
360 	}
361 
362 	if (buf[0] == ATT_OP_ERROR) {
363 		status = buf[4];
364 		goto done;
365 	}
366 
367 	if (cmd->expected != buf[0]) {
368 		status = ATT_ECODE_IO;
369 		goto done;
370 	}
371 
372 	status = 0;
373 
374 done:
375 	qempty = attrib->queue == NULL || g_queue_is_empty(attrib->queue);
376 
377 	if (cmd) {
378 		if (cmd->func)
379 			cmd->func(status, buf, len, cmd->user_data);
380 
381 		command_destroy(cmd);
382 	}
383 
384 	if (!qempty)
385 		wake_up_sender(attrib);
386 
387 	return TRUE;
388 }
389 
g_attrib_new(GIOChannel * io)390 GAttrib *g_attrib_new(GIOChannel *io)
391 {
392 	struct _GAttrib *attrib;
393 	uint16_t omtu;
394 
395 	g_io_channel_set_encoding(io, NULL, NULL);
396 	g_io_channel_set_buffered(io, FALSE);
397 
398 	attrib = g_try_new0(struct _GAttrib, 1);
399 	if (attrib == NULL)
400 		return NULL;
401 
402 	attrib->io = g_io_channel_ref(io);
403 	attrib->queue = g_queue_new();
404 
405 	attrib->read_watch = g_io_add_watch(attrib->io,
406 			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
407 			received_data, attrib);
408 
409 	if (bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
410 			BT_IO_OPT_OMTU, &omtu,
411 			BT_IO_OPT_INVALID)) {
412 		if (omtu == 0 || omtu > ATT_MAX_MTU)
413 			omtu = ATT_MAX_MTU;
414 	} else
415 		omtu = ATT_DEFAULT_LE_MTU;
416 
417 	attrib->buf = g_malloc0(omtu);
418 	attrib->buflen = omtu;
419 
420 	return g_attrib_ref(attrib);
421 }
422 
g_attrib_send(GAttrib * attrib,guint id,guint8 opcode,const guint8 * pdu,guint16 len,GAttribResultFunc func,gpointer user_data,GDestroyNotify notify)423 guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
424 			const guint8 *pdu, guint16 len, GAttribResultFunc func,
425 			gpointer user_data, GDestroyNotify notify)
426 {
427 	struct command *c;
428 
429 	c = g_try_new0(struct command, 1);
430 	if (c == NULL)
431 		return 0;
432 
433 	c->opcode = opcode;
434 	c->expected = opcode2expected(opcode);
435 	c->pdu = g_malloc(len);
436 	memcpy(c->pdu, pdu, len);
437 	c->len = len;
438 	c->func = func;
439 	c->user_data = user_data;
440 	c->notify = notify;
441 
442 	if (id) {
443 		c->id = id;
444 		g_queue_push_head(attrib->queue, c);
445 	} else {
446 		c->id = ++attrib->next_cmd_id;
447 		g_queue_push_tail(attrib->queue, c);
448 	}
449 
450 	if (g_queue_get_length(attrib->queue) == 1)
451 		wake_up_sender(attrib);
452 
453 	return c->id;
454 }
455 
command_cmp_by_id(gconstpointer a,gconstpointer b)456 static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
457 {
458 	const struct command *cmd = a;
459 	guint id = GPOINTER_TO_UINT(b);
460 
461 	return cmd->id - id;
462 }
463 
g_attrib_cancel(GAttrib * attrib,guint id)464 gboolean g_attrib_cancel(GAttrib *attrib, guint id)
465 {
466 	GList *l;
467 	struct command *cmd;
468 
469 	if (attrib == NULL || attrib->queue == NULL)
470 		return FALSE;
471 
472 	l = g_queue_find_custom(attrib->queue, GUINT_TO_POINTER(id),
473 							command_cmp_by_id);
474 	if (l == NULL)
475 		return FALSE;
476 
477 	cmd = l->data;
478 
479 	if (cmd == g_queue_peek_head(attrib->queue) && cmd->sent)
480 		cmd->func = NULL;
481 	else {
482 		g_queue_remove(attrib->queue, cmd);
483 		command_destroy(cmd);
484 	}
485 
486 	return TRUE;
487 }
488 
g_attrib_cancel_all(GAttrib * attrib)489 gboolean g_attrib_cancel_all(GAttrib *attrib)
490 {
491 	struct command *c, *head = NULL;
492 	gboolean first = TRUE;
493 
494 	if (attrib == NULL || attrib->queue == NULL)
495 		return FALSE;
496 
497 	while ((c = g_queue_pop_head(attrib->queue))) {
498 		if (first && c->sent) {
499 			/* If the command was sent ignore its callback ... */
500 			c->func = NULL;
501 			head = c;
502 			continue;
503 		}
504 
505 		first = FALSE;
506 		command_destroy(c);
507 	}
508 
509 	if (head) {
510 		/* ... and put it back in the queue */
511 		g_queue_push_head(attrib->queue, head);
512 	}
513 
514 	return TRUE;
515 }
516 
g_attrib_set_debug(GAttrib * attrib,GAttribDebugFunc func,gpointer user_data)517 gboolean g_attrib_set_debug(GAttrib *attrib,
518 		GAttribDebugFunc func, gpointer user_data)
519 {
520 	return TRUE;
521 }
522 
g_attrib_get_buffer(GAttrib * attrib,int * len)523 uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len)
524 {
525 	if (len == NULL)
526 		return NULL;
527 
528 	*len = attrib->buflen;
529 
530 	return attrib->buf;
531 }
532 
g_attrib_set_mtu(GAttrib * attrib,int mtu)533 gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
534 {
535 	if (mtu < ATT_DEFAULT_LE_MTU)
536 		mtu = ATT_DEFAULT_LE_MTU;
537 
538 	if (mtu > ATT_MAX_MTU)
539 		mtu = ATT_MAX_MTU;
540 
541 	if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL,
542 			BT_IO_OPT_OMTU, mtu,
543 			BT_IO_OPT_INVALID))
544 		return FALSE;
545 
546 	attrib->buf = g_realloc(attrib->buf, mtu);
547 
548 	attrib->buflen = mtu;
549 
550 	return TRUE;
551 }
552 
g_attrib_register(GAttrib * attrib,guint8 opcode,GAttribNotifyFunc func,gpointer user_data,GDestroyNotify notify)553 guint g_attrib_register(GAttrib *attrib, guint8 opcode,
554 				GAttribNotifyFunc func, gpointer user_data,
555 				GDestroyNotify notify)
556 {
557 	struct event *event;
558 
559 	event = g_try_new0(struct event, 1);
560 	if (event == NULL)
561 		return 0;
562 
563 	event->expected = opcode;
564 	event->func = func;
565 	event->user_data = user_data;
566 	event->notify = notify;
567 	event->id = ++attrib->next_evt_id;
568 
569 	attrib->events = g_slist_append(attrib->events, event);
570 
571 	return event->id;
572 }
573 
event_cmp_by_id(gconstpointer a,gconstpointer b)574 static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
575 {
576 	const struct event *evt = a;
577 	guint id = GPOINTER_TO_UINT(b);
578 
579 	return evt->id - id;
580 }
581 
g_attrib_is_encrypted(GAttrib * attrib)582 gboolean g_attrib_is_encrypted(GAttrib *attrib)
583 {
584 	BtIOSecLevel sec_level;
585 
586 	if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
587 			BT_IO_OPT_SEC_LEVEL, &sec_level,
588 			BT_IO_OPT_INVALID))
589 		return FALSE;
590 
591 	return sec_level > BT_IO_SEC_LOW;
592 }
593 
g_attrib_unregister(GAttrib * attrib,guint id)594 gboolean g_attrib_unregister(GAttrib *attrib, guint id)
595 {
596 	struct event *evt;
597 	GSList *l;
598 
599 	l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
600 							event_cmp_by_id);
601 	if (l == NULL)
602 		return FALSE;
603 
604 	evt = l->data;
605 
606 	attrib->events = g_slist_remove(attrib->events, evt);
607 
608 	if (evt->notify)
609 		evt->notify(evt->user_data);
610 
611 	g_free(evt);
612 
613 	return TRUE;
614 }
615 
g_attrib_unregister_all(GAttrib * attrib)616 gboolean g_attrib_unregister_all(GAttrib *attrib)
617 {
618 	GSList *l;
619 
620 	if (attrib->events == NULL)
621 		return FALSE;
622 
623 	for (l = attrib->events; l; l = l->next) {
624 		struct event *evt = l->data;
625 
626 		if (evt->notify)
627 			evt->notify(evt->user_data);
628 
629 		g_free(evt);
630 	}
631 
632 	g_slist_free(attrib->events);
633 	attrib->events = NULL;
634 
635 	return TRUE;
636 }
637