Home | History | Annotate | Download | only in attrib
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2010  Nokia Corporation
      6  *  Copyright (C) 2010  Marcel Holtmann <marcel (at) 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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    217 GIOChannel *g_attrib_get_channel(GAttrib *attrib)
    218 {
    219 	if (!attrib)
    220 		return NULL;
    221 
    222 	return attrib->io;
    223 }
    224 
    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 
    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 
    249 static gboolean disconnect_timeout(gpointer data)
    250 {
    251 	struct _GAttrib *attrib = data;
    252 
    253 	attrib_destroy(attrib);
    254 
    255 	return FALSE;
    256 }
    257 
    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 
    299 static void destroy_sender(gpointer data)
    300 {
    301 	struct _GAttrib *attrib = data;
    302 
    303 	attrib->write_watch = 0;
    304 }
    305 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    517 gboolean g_attrib_set_debug(GAttrib *attrib,
    518 		GAttribDebugFunc func, gpointer user_data)
    519 {
    520 	return TRUE;
    521 }
    522 
    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 
    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 
    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 
    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 
    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 
    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 
    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