proxy.c revision 31079f3b1baffe70a717a01e60eacfa6930a9ba7
1/*
2 *
3 *  BlueZ - Bluetooth protocol stack for Linux
4 *
5 *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
6 *
7 *
8 *  This program is free software; you can redistribute it and/or modify
9 *  it under the terms of the GNU General Public License as published by
10 *  the Free Software Foundation; either version 2 of the License, or
11 *  (at your option) any later version.
12 *
13 *  This program is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *  GNU General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this program; if not, write to the Free Software
20 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 */
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <ctype.h>
29#include <dirent.h>
30#include <errno.h>
31#include <fcntl.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <termios.h>
36#include <unistd.h>
37#include <arpa/inet.h>
38#include <sys/param.h>
39#include <sys/ioctl.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/un.h>
43
44#include <bluetooth/bluetooth.h>
45#include <bluetooth/sdp.h>
46#include <bluetooth/sdp_lib.h>
47#include <bluetooth/rfcomm.h>
48
49#include <glib.h>
50#include <gdbus.h>
51
52#include "../src/dbus-common.h"
53#include "../src/adapter.h"
54
55#include "log.h"
56#include "textfile.h"
57
58#include "error.h"
59#include "sdpd.h"
60#include "glib-helper.h"
61#include "btio.h"
62#include "proxy.h"
63
64#define SERIAL_PROXY_INTERFACE	"org.bluez.SerialProxy"
65#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
66#define BUF_SIZE		1024
67
68typedef enum {
69	TTY_PROXY,
70	UNIX_SOCKET_PROXY,
71	TCP_SOCKET_PROXY,
72	UNKNOWN_PROXY_TYPE = 0xFF
73} proxy_type_t;
74
75struct serial_adapter {
76	struct btd_adapter	*btd_adapter;	/* Adapter pointer */
77	DBusConnection		*conn;		/* Adapter connection */
78	GSList			*proxies;	/* Proxies list */
79};
80
81struct serial_proxy {
82	bdaddr_t	src;		/* Local address */
83	bdaddr_t	dst;		/* Remote address */
84	char		*path;		/* Proxy path */
85	char		*uuid128;	/* UUID 128 */
86	char		*address;	/* TTY or Unix socket name */
87	char		*owner;		/* Application bus name */
88	guint		watch;		/* Application watch */
89	short int	port;		/* TCP port */
90	proxy_type_t	type;		/* TTY or Unix socket */
91	struct termios  sys_ti;		/* Default TTY setting */
92	struct termios  proxy_ti;	/* Proxy TTY settings */
93	uint8_t		channel;	/* RFCOMM channel */
94	uint32_t	record_id;	/* Service record id */
95	GIOChannel	*io;		/* Server listen */
96	GIOChannel	*rfcomm;	/* Remote RFCOMM channel*/
97	GIOChannel	*local;		/* Local channel: TTY or Unix socket */
98	struct serial_adapter *adapter;	/* Adapter pointer */
99};
100
101static GSList *adapters = NULL;
102static int sk_counter = 0;
103
104static void disable_proxy(struct serial_proxy *prx)
105{
106	if (prx->rfcomm) {
107		g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
108		g_io_channel_unref(prx->rfcomm);
109		prx->rfcomm = NULL;
110	}
111
112	if (prx->local) {
113		g_io_channel_shutdown(prx->local, TRUE, NULL);
114		g_io_channel_unref(prx->local);
115		prx->local = NULL;
116	}
117
118	remove_record_from_server(prx->record_id);
119	prx->record_id = 0;
120
121	g_io_channel_unref(prx->io);
122	prx->io = NULL;
123}
124
125static void proxy_free(struct serial_proxy *prx)
126{
127	g_free(prx->owner);
128	g_free(prx->path);
129	g_free(prx->address);
130	g_free(prx->uuid128);
131	g_free(prx);
132}
133
134static void add_lang_attr(sdp_record_t *r)
135{
136	sdp_lang_attr_t base_lang;
137	sdp_list_t *langs = 0;
138
139	/* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */
140	base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
141	base_lang.encoding = 106;
142	base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
143	langs = sdp_list_append(0, &base_lang);
144	sdp_set_lang_attr(r, langs);
145	sdp_list_free(langs, 0);
146}
147
148static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
149{
150	sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
151	uuid_t uuid, root_uuid, l2cap, rfcomm;
152	sdp_profile_desc_t profile;
153	sdp_record_t *record;
154	sdp_data_t *ch;
155
156	record = sdp_record_alloc();
157	if (!record)
158		return NULL;
159
160	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
161	root = sdp_list_append(NULL, &root_uuid);
162	sdp_set_browse_groups(record, root);
163	sdp_list_free(root, NULL);
164
165	bt_string2uuid(&uuid, uuid128);
166	sdp_uuid128_to_uuid(&uuid);
167	svclass_id = sdp_list_append(NULL, &uuid);
168	sdp_set_service_classes(record, svclass_id);
169	sdp_list_free(svclass_id, NULL);
170
171	sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
172	profile.version = 0x0100;
173	profiles = sdp_list_append(NULL, &profile);
174	sdp_set_profile_descs(record, profiles);
175	sdp_list_free(profiles, NULL);
176
177	sdp_uuid16_create(&l2cap, L2CAP_UUID);
178	proto[0] = sdp_list_append(NULL, &l2cap);
179	apseq = sdp_list_append(NULL, proto[0]);
180
181	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
182	proto[1] = sdp_list_append(NULL, &rfcomm);
183	ch = sdp_data_alloc(SDP_UINT8, &channel);
184	proto[1] = sdp_list_append(proto[1], ch);
185	apseq = sdp_list_append(apseq, proto[1]);
186
187	aproto = sdp_list_append(NULL, apseq);
188	sdp_set_access_protos(record, aproto);
189
190	add_lang_attr(record);
191
192	sdp_set_info_attr(record, "Serial Proxy", NULL, "Serial Proxy");
193
194	sdp_data_free(ch);
195	sdp_list_free(proto[0], NULL);
196	sdp_list_free(proto[1], NULL);
197	sdp_list_free(apseq, NULL);
198	sdp_list_free(aproto, NULL);
199
200	return record;
201}
202
203static int channel_write(GIOChannel *chan, char *buf, size_t size)
204{
205	size_t wbytes;
206	ssize_t written;
207	int fd;
208
209	fd = g_io_channel_unix_get_fd(chan);
210
211	wbytes = 0;
212	while (wbytes < size) {
213		written = write(fd, buf + wbytes, size - wbytes);
214
215		if (written)
216			return -errno;
217
218		wbytes += written;
219	}
220
221	return 0;
222}
223
224static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data)
225{
226	char buf[BUF_SIZE];
227	struct serial_proxy *prx = data;
228	GIOChannel *dest;
229	ssize_t rbytes;
230	int fd, err;
231
232	if (cond & G_IO_NVAL)
233		return FALSE;
234
235	dest = (chan == prx->rfcomm) ? prx->local : prx->rfcomm;
236
237	fd = g_io_channel_unix_get_fd(chan);
238
239	if (cond & (G_IO_HUP | G_IO_ERR)) {
240		/* Try forward remaining data */
241		do {
242			rbytes = read(fd, buf, sizeof(buf));
243			if (rbytes <= 0)
244				break;
245
246			err = channel_write(dest, buf, rbytes);
247		} while (err == 0);
248
249		g_io_channel_shutdown(prx->local, TRUE, NULL);
250		g_io_channel_unref(prx->local);
251		prx->local = NULL;
252
253		g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
254		g_io_channel_unref(prx->rfcomm);
255		prx->rfcomm = NULL;
256
257		return FALSE;
258	}
259
260	rbytes = read(fd, buf, sizeof(buf));
261	if (rbytes < 0)
262		return FALSE;
263
264	err = channel_write(dest, buf, rbytes);
265	if (err != 0)
266		return FALSE;
267
268	return TRUE;
269}
270
271static inline int unix_socket_connect(const char *address)
272{
273	struct sockaddr_un addr;
274	int err, sk;
275
276	memset(&addr, 0, sizeof(addr));
277	addr.sun_family = PF_UNIX;
278
279	if (strncmp("x00", address, 3) == 0) {
280		/*
281		 * Abstract namespace: first byte NULL, x00
282		 * must be removed from the original address.
283		 */
284		strncpy(addr.sun_path + 1, address + 3,
285						sizeof(addr.sun_path) - 2);
286	} else {
287		/* Filesystem address */
288		strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1);
289	}
290
291	/* Unix socket */
292	sk = socket(AF_UNIX, SOCK_STREAM, 0);
293	if (sk < 0) {
294		err = errno;
295		error("Unix socket(%s) create failed: %s(%d)",
296				address, strerror(err), err);
297		return -err;
298	}
299
300	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
301		err = errno;
302		error("Unix socket(%s) connect failed: %s(%d)",
303				address, strerror(err), err);
304		close(sk);
305		errno = err;
306		return -err;
307	}
308
309	return sk;
310}
311
312static int tcp_socket_connect(const char *address)
313{
314	struct sockaddr_in addr;
315	int err, sk;
316	unsigned short int port;
317
318	memset(&addr, 0, sizeof(addr));
319
320	if (strncmp(address, "localhost", 9) != 0) {
321		error("Address should have the form localhost:port.");
322		return -1;
323	}
324	port = atoi(strchr(address, ':') + 1);
325	if (port <= 0) {
326		error("Invalid port '%d'.", port);
327		return -1;
328	}
329	addr.sin_family = AF_INET;
330	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
331	addr.sin_port = htons(port);
332
333	sk = socket(PF_INET, SOCK_STREAM, 0);
334	if (sk < 0) {
335		err = errno;
336		error("TCP socket(%s) create failed %s(%d)", address,
337							strerror(err), err);
338		return -err;
339	}
340	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
341		err = errno;
342		error("TCP socket(%s) connect failed: %s(%d)",
343						address, strerror(err), err);
344		close(sk);
345		errno = err;
346		return -err;
347	}
348	return sk;
349}
350
351static inline int tty_open(const char *tty, struct termios *ti)
352{
353	int err, sk;
354
355	sk = open(tty, O_RDWR | O_NOCTTY);
356	if (sk < 0) {
357		err = errno;
358		error("Can't open TTY %s: %s(%d)", tty, strerror(err), err);
359		return -err;
360	}
361
362	if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
363		err = errno;
364		error("Can't change serial settings: %s(%d)",
365				strerror(err), err);
366		close(sk);
367		errno = err;
368		return -err;
369	}
370
371	return sk;
372}
373
374static void connect_event_cb(GIOChannel *chan, GError *conn_err, gpointer data)
375{
376	struct serial_proxy *prx = data;
377	int sk;
378
379	if (conn_err) {
380		error("%s", conn_err->message);
381		goto drop;
382	}
383
384	/* Connect local */
385	switch (prx->type) {
386	case UNIX_SOCKET_PROXY:
387		sk = unix_socket_connect(prx->address);
388		break;
389	case TTY_PROXY:
390		sk = tty_open(prx->address, &prx->proxy_ti);
391		break;
392	case TCP_SOCKET_PROXY:
393		sk = tcp_socket_connect(prx->address);
394		break;
395	default:
396		sk = -1;
397	}
398
399	if (sk < 0)
400		goto drop;
401
402	prx->local = g_io_channel_unix_new(sk);
403
404	g_io_add_watch(prx->rfcomm,
405			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
406			forward_data, prx);
407
408	g_io_add_watch(prx->local,
409			G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
410			forward_data, prx);
411
412	return;
413
414drop:
415	g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
416	g_io_channel_unref(prx->rfcomm);
417	prx->rfcomm = NULL;
418}
419
420static void auth_cb(DBusError *derr, void *user_data)
421{
422	struct serial_proxy *prx = user_data;
423	GError *err = NULL;
424
425	if (derr) {
426		error("Access denied: %s", derr->message);
427		goto reject;
428	}
429
430	if (!bt_io_accept(prx->rfcomm, connect_event_cb, prx, NULL,
431							&err)) {
432		error("bt_io_accept: %s", err->message);
433		g_error_free(err);
434		goto reject;
435	}
436
437	return;
438
439reject:
440	g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
441	g_io_channel_unref(prx->rfcomm);
442	prx->rfcomm = NULL;
443}
444
445static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
446{
447	struct serial_proxy *prx = user_data;
448	int perr;
449	char address[18];
450	GError *err = NULL;
451
452	bt_io_get(chan, BT_IO_RFCOMM, &err,
453			BT_IO_OPT_DEST_BDADDR, &prx->dst,
454			BT_IO_OPT_DEST, address,
455			BT_IO_OPT_INVALID);
456	if (err) {
457		error("%s", err->message);
458		g_error_free(err);
459		goto drop;
460	}
461
462	if (prx->rfcomm) {
463		error("Refusing connect from %s: Proxy already in use",
464				address);
465		goto drop;
466	}
467
468	DBG("Serial Proxy: incoming connect from %s", address);
469
470	prx->rfcomm = g_io_channel_ref(chan);
471
472	perr = btd_request_authorization(&prx->src, &prx->dst,
473					prx->uuid128, auth_cb, prx);
474	if (perr < 0) {
475		error("Refusing connect from %s: %s (%d)", address,
476				strerror(-perr), -perr);
477		g_io_channel_unref(prx->rfcomm);
478		prx->rfcomm = NULL;
479		goto drop;
480	}
481
482	return;
483
484drop:
485	g_io_channel_shutdown(chan, TRUE, NULL);
486}
487
488static int enable_proxy(struct serial_proxy *prx)
489{
490	sdp_record_t *record;
491	GError *gerr = NULL;
492	int err;
493
494	if (prx->io)
495		return -EALREADY;
496
497	/* Listen */
498	prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
499				NULL, &gerr,
500				BT_IO_OPT_SOURCE_BDADDR, &prx->src,
501				BT_IO_OPT_INVALID);
502	if (!prx->io)
503		goto failed;
504
505	bt_io_get(prx->io, BT_IO_RFCOMM, &gerr,
506			BT_IO_OPT_CHANNEL, &prx->channel,
507			BT_IO_OPT_INVALID);
508	if (gerr) {
509		g_io_channel_unref(prx->io);
510		prx->io = NULL;
511		goto failed;
512	}
513
514	DBG("Allocated channel %d", prx->channel);
515
516	g_io_channel_set_close_on_unref(prx->io, TRUE);
517
518	record = proxy_record_new(prx->uuid128, prx->channel);
519	if (!record) {
520		g_io_channel_unref(prx->io);
521		return -ENOMEM;
522	}
523
524	err = add_record_to_server(&prx->src, record);
525	if (err < 0) {
526		sdp_record_free(record);
527		g_io_channel_unref(prx->io);
528		return err;
529	}
530
531	prx->record_id = record->handle;
532
533	return 0;
534
535failed:
536	error("%s", gerr->message);
537	g_error_free(gerr);
538	return -EIO;
539
540}
541static DBusMessage *proxy_enable(DBusConnection *conn,
542				DBusMessage *msg, void *data)
543{
544	struct serial_proxy *prx = data;
545	int err;
546
547	err = enable_proxy(prx);
548	if (err < 0)
549		return btd_error_failed(msg, strerror(-err));
550
551	return dbus_message_new_method_return(msg);
552}
553
554static DBusMessage *proxy_disable(DBusConnection *conn,
555				DBusMessage *msg, void *data)
556{
557	struct serial_proxy *prx = data;
558
559	if (!prx->io)
560		return btd_error_failed(msg, "Not enabled");
561
562	/* Remove the watches and unregister the record */
563	disable_proxy(prx);
564
565	return dbus_message_new_method_return(msg);
566}
567
568static DBusMessage *proxy_get_info(DBusConnection *conn,
569				DBusMessage *msg, void *data)
570{
571	struct serial_proxy *prx = data;
572	DBusMessage *reply;
573	DBusMessageIter iter, dict;
574	dbus_bool_t boolean;
575
576	reply = dbus_message_new_method_return(msg);
577	if (!reply)
578		return NULL;
579
580	dbus_message_iter_init_append(reply, &iter);
581
582	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
583			DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
584			DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
585			DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
586
587	dict_append_entry(&dict, "uuid", DBUS_TYPE_STRING, &prx->uuid128);
588
589	dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &prx->address);
590
591	if (prx->channel)
592		dict_append_entry(&dict, "channel",
593					DBUS_TYPE_BYTE, &prx->channel);
594
595	boolean = (prx->io ? TRUE : FALSE);
596	dict_append_entry(&dict, "enabled", DBUS_TYPE_BOOLEAN, &boolean);
597
598	boolean = (prx->rfcomm ? TRUE : FALSE);
599	dict_append_entry(&dict, "connected", DBUS_TYPE_BOOLEAN, &boolean);
600
601	/* If connected: append the remote address */
602	if (boolean) {
603		char bda[18];
604		const char *pstr = bda;
605
606		ba2str(&prx->dst, bda);
607		dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &pstr);
608	}
609
610	dbus_message_iter_close_container(&iter, &dict);
611
612	return reply;
613}
614
615static struct {
616	const char	*str;
617	speed_t		speed;
618} supported_speed[]  = {
619	{"50",		B50	},
620	{"300",		B300	},
621	{"600",		B600	},
622	{"1200",	B1200	},
623	{"1800",	B1800	},
624	{"2400",	B2400	},
625	{"4800",	B4800	},
626	{"9600",	B9600	},
627	{"19200",	B19200	},
628	{"38400",	B38400	},
629	{"57600",	B57600	},
630	{"115200",	B115200	},
631	{ NULL,		B0	}
632};
633
634static speed_t str2speed(const char *str, speed_t *speed)
635{
636	int i;
637
638	for (i = 0; supported_speed[i].str; i++) {
639		if (strcmp(supported_speed[i].str, str) != 0)
640			continue;
641
642		if (speed)
643			*speed = supported_speed[i].speed;
644
645		return supported_speed[i].speed;
646	}
647
648	return B0;
649}
650
651static int set_parity(const char *str, tcflag_t *ctrl)
652{
653	if (strcasecmp("even", str) == 0) {
654		*ctrl |= PARENB;
655		*ctrl &= ~PARODD;
656	} else if (strcasecmp("odd", str) == 0) {
657		*ctrl |= PARENB;
658		*ctrl |= PARODD;
659	} else if (strcasecmp("mark", str) == 0)
660		*ctrl |= PARENB;
661	else if ((strcasecmp("none", str) == 0) ||
662			(strcasecmp("space", str) == 0))
663		*ctrl &= ~PARENB;
664	else
665		return -1;
666
667	return 0;
668}
669
670static int set_databits(uint8_t databits, tcflag_t *ctrl)
671{
672	if (databits < 5 || databits > 8)
673		return -EINVAL;
674
675	*ctrl &= ~CSIZE;
676	switch (databits) {
677	case 5:
678		*ctrl |= CS5;
679		break;
680	case 6:
681		*ctrl |= CS6;
682		break;
683	case 7:
684		*ctrl |= CS7;
685		break;
686	case 8:
687		*ctrl |= CS8;
688		break;
689	}
690
691	return 0;
692}
693
694static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl)
695{
696	/* 1.5 will not be allowed */
697	switch (stopbits) {
698	case 1:
699		*ctrl &= ~CSTOPB;
700		return 0;
701	case 2:
702		*ctrl |= CSTOPB;
703		return 0;
704	}
705
706	return -EINVAL;
707}
708
709static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
710						DBusMessage *msg, void *data)
711{
712	struct serial_proxy *prx = data;
713	const char *ratestr, *paritystr;
714	uint8_t databits, stopbits;
715	tcflag_t ctrl;		/* Control mode flags */
716	speed_t speed = B0;	/* In/Out speed */
717
718	/* Don't allow change TTY settings if it is open */
719	if (prx->local)
720		return btd_error_not_authorized(msg);
721
722	if (!dbus_message_get_args(msg, NULL,
723				DBUS_TYPE_STRING, &ratestr,
724				DBUS_TYPE_BYTE, &databits,
725				DBUS_TYPE_BYTE, &stopbits,
726				DBUS_TYPE_STRING, &paritystr,
727				DBUS_TYPE_INVALID))
728		return NULL;
729
730	if (str2speed(ratestr, &speed)  == B0)
731		return btd_error_invalid_args(msg);
732
733	ctrl = prx->proxy_ti.c_cflag;
734	if (set_databits(databits, &ctrl) < 0)
735		return btd_error_invalid_args(msg);
736
737	if (set_stopbits(stopbits, &ctrl) < 0)
738		return btd_error_invalid_args(msg);
739
740	if (set_parity(paritystr, &ctrl) < 0)
741		return btd_error_invalid_args(msg);
742
743	prx->proxy_ti.c_cflag = ctrl;
744	prx->proxy_ti.c_cflag |= (CLOCAL | CREAD);
745	cfsetispeed(&prx->proxy_ti, speed);
746	cfsetospeed(&prx->proxy_ti, speed);
747
748	return dbus_message_new_method_return(msg);
749}
750
751static GDBusMethodTable proxy_methods[] = {
752	{ "Enable",			"",	"",	proxy_enable },
753	{ "Disable",			"",	"",	proxy_disable },
754	{ "GetInfo",			"",	"a{sv}",proxy_get_info },
755	{ "SetSerialParameters",	"syys",	"",	proxy_set_serial_params },
756	{ },
757};
758
759static void proxy_path_unregister(gpointer data)
760{
761	struct serial_proxy *prx = data;
762	int sk;
763
764	DBG("Unregistered proxy: %s", prx->address);
765
766	if (prx->type != TTY_PROXY)
767		goto done;
768
769	/* Restore the initial TTY configuration */
770	sk = open(prx->address, O_RDWR | O_NOCTTY);
771	if (sk >= 0) {
772		tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
773		close(sk);
774	}
775done:
776
777	proxy_free(prx);
778}
779
780static int register_proxy_object(struct serial_proxy *prx)
781{
782	struct serial_adapter *adapter = prx->adapter;
783	char path[MAX_PATH_LENGTH + 1];
784
785	snprintf(path, MAX_PATH_LENGTH, "%s/proxy%d",
786			adapter_get_path(adapter->btd_adapter), sk_counter++);
787
788	if (!g_dbus_register_interface(adapter->conn, path,
789					SERIAL_PROXY_INTERFACE,
790					proxy_methods, NULL, NULL,
791					prx, proxy_path_unregister)) {
792		error("D-Bus failed to register %s path", path);
793		return -1;
794	}
795
796	prx->path = g_strdup(path);
797	adapter->proxies = g_slist_append(adapter->proxies, prx);
798
799	DBG("Registered proxy: %s", path);
800
801	return 0;
802}
803
804static int proxy_tty_register(struct serial_adapter *adapter,
805				const char *uuid128, const char *address,
806				struct termios *ti,
807				struct serial_proxy **proxy)
808{
809	struct termios sys_ti;
810	struct serial_proxy *prx;
811	int sk, ret;
812
813	sk = open(address, O_RDONLY | O_NOCTTY);
814	if (sk < 0) {
815		error("Cant open TTY: %s(%d)", strerror(errno), errno);
816		return -EINVAL;
817	}
818
819	prx = g_new0(struct serial_proxy, 1);
820	prx->address = g_strdup(address);
821	prx->uuid128 = g_strdup(uuid128);
822	prx->type = TTY_PROXY;
823	adapter_get_address(adapter->btd_adapter, &prx->src);
824	prx->adapter = adapter;
825
826	/* Current TTY settings */
827	memset(&sys_ti, 0, sizeof(sys_ti));
828	tcgetattr(sk, &sys_ti);
829	memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
830	close(sk);
831
832	if (!ti) {
833		/* Use current settings */
834		memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
835	} else {
836		/* New TTY settings: user provided */
837		memcpy(&prx->proxy_ti, ti, sizeof(*ti));
838	}
839
840	ret = register_proxy_object(prx);
841	if (ret < 0) {
842		proxy_free(prx);
843		return ret;
844	}
845
846	*proxy = prx;
847
848	return ret;
849}
850
851static int proxy_socket_register(struct serial_adapter *adapter,
852				const char *uuid128, const char *address,
853				struct serial_proxy **proxy)
854{
855	struct serial_proxy *prx;
856	int ret;
857
858	prx = g_new0(struct serial_proxy, 1);
859	prx->address = g_strdup(address);
860	prx->uuid128 = g_strdup(uuid128);
861	prx->type = UNIX_SOCKET_PROXY;
862	adapter_get_address(adapter->btd_adapter, &prx->src);
863	prx->adapter = adapter;
864
865	ret = register_proxy_object(prx);
866	if (ret < 0) {
867		proxy_free(prx);
868		return ret;
869	}
870
871	*proxy = prx;
872
873	return ret;
874}
875
876static int proxy_tcp_register(struct serial_adapter *adapter,
877				const char *uuid128, const char *address,
878				struct serial_proxy **proxy)
879{
880	struct serial_proxy *prx;
881	int ret;
882
883	prx = g_new0(struct serial_proxy, 1);
884	prx->address = g_strdup(address);
885	prx->uuid128 = g_strdup(uuid128);
886	prx->type = TCP_SOCKET_PROXY;
887	adapter_get_address(adapter->btd_adapter, &prx->src);
888	prx->adapter = adapter;
889
890	ret = register_proxy_object(prx);
891	if (ret < 0) {
892		proxy_free(prx);
893		return ret;
894	}
895
896	*proxy = prx;
897
898	return ret;
899}
900
901static proxy_type_t addr2type(const char *address)
902{
903	struct stat st;
904
905	if (stat(address, &st) < 0) {
906		/*
907		 * Unix socket: if the sun_path starts with null byte
908		 * it refers to abstract namespace. 'x00' will be used
909		 * to represent the null byte.
910		 */
911		if (strncmp("localhost:", address, 10) == 0)
912			return TCP_SOCKET_PROXY;
913		if (strncmp("x00", address, 3) != 0)
914			return UNKNOWN_PROXY_TYPE;
915		else
916			return UNIX_SOCKET_PROXY;
917	} else {
918		/* Filesystem: char device or unix socket */
919		if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
920			return TTY_PROXY;
921		else if (S_ISSOCK(st.st_mode))
922			return UNIX_SOCKET_PROXY;
923		else
924			return UNKNOWN_PROXY_TYPE;
925	}
926}
927
928static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr)
929{
930	const struct serial_proxy *prx = proxy;
931	const char *address = addr;
932
933	return strcmp(prx->address, address);
934}
935
936static int proxy_pathcmp(gconstpointer proxy, gconstpointer p)
937{
938	const struct serial_proxy *prx = proxy;
939	const char *path = p;
940
941	return strcmp(prx->path, path);
942}
943
944static int register_proxy(struct serial_adapter *adapter,
945				const char *uuid_str, const char *address,
946				struct serial_proxy **proxy)
947{
948	proxy_type_t type;
949	int err;
950
951	type = addr2type(address);
952	if (type == UNKNOWN_PROXY_TYPE)
953		return -EINVAL;
954
955	/* Only one proxy per address(TTY or unix socket) is allowed */
956	if (g_slist_find_custom(adapter->proxies, address, proxy_addrcmp))
957		return -EALREADY;
958
959	switch (type) {
960	case UNIX_SOCKET_PROXY:
961		err = proxy_socket_register(adapter, uuid_str, address, proxy);
962		break;
963	case TTY_PROXY:
964		err = proxy_tty_register(adapter, uuid_str, address, NULL,
965					proxy);
966		break;
967	case TCP_SOCKET_PROXY:
968		err = proxy_tcp_register(adapter, uuid_str, address, proxy);
969		break;
970	default:
971		err = -EINVAL;
972	}
973
974	if (err < 0)
975		return err;
976
977	g_dbus_emit_signal(adapter->conn,
978				adapter_get_path(adapter->btd_adapter),
979				SERIAL_MANAGER_INTERFACE, "ProxyCreated",
980				DBUS_TYPE_STRING, &(*proxy)->path,
981				DBUS_TYPE_INVALID);
982
983	return 0;
984}
985
986static void unregister_proxy(struct serial_proxy *proxy)
987{
988	struct serial_adapter *adapter = proxy->adapter;
989	char *path = g_strdup(proxy->path);
990
991	if (proxy->watch > 0)
992		g_dbus_remove_watch(adapter->conn, proxy->watch);
993
994	g_dbus_emit_signal(adapter->conn,
995			adapter_get_path(adapter->btd_adapter),
996			SERIAL_MANAGER_INTERFACE, "ProxyRemoved",
997			DBUS_TYPE_STRING, &path,
998			DBUS_TYPE_INVALID);
999
1000	adapter->proxies = g_slist_remove(adapter->proxies, proxy);
1001
1002	g_dbus_unregister_interface(adapter->conn, path,
1003					SERIAL_PROXY_INTERFACE);
1004
1005	g_free(path);
1006}
1007
1008static void watch_proxy(DBusConnection *connection, void *user_data)
1009{
1010	struct serial_proxy *proxy = user_data;
1011
1012	proxy->watch = 0;
1013	unregister_proxy(proxy);
1014}
1015
1016static DBusMessage *create_proxy(DBusConnection *conn,
1017				DBusMessage *msg, void *data)
1018{
1019	struct serial_adapter *adapter = data;
1020	struct serial_proxy *proxy;
1021	const char *pattern, *address;
1022	char *uuid_str;
1023	int err;
1024
1025	if (!dbus_message_get_args(msg, NULL,
1026				DBUS_TYPE_STRING, &pattern,
1027				DBUS_TYPE_STRING, &address,
1028				DBUS_TYPE_INVALID))
1029		return NULL;
1030
1031	uuid_str = bt_name2string(pattern);
1032	if (!uuid_str)
1033		return btd_error_invalid_args(msg);
1034
1035	err = register_proxy(adapter, uuid_str, address, &proxy);
1036	g_free(uuid_str);
1037
1038	if (err == -EINVAL)
1039		return btd_error_invalid_args(msg);
1040	else if (err == -EALREADY)
1041		return btd_error_already_exists(msg);
1042	else if (err < 0)
1043		return btd_error_failed(msg, strerror(-err));
1044
1045	proxy->owner = g_strdup(dbus_message_get_sender(msg));
1046	proxy->watch = g_dbus_add_disconnect_watch(conn, proxy->owner,
1047						watch_proxy,
1048						proxy, NULL);
1049
1050	return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &proxy->path,
1051					DBUS_TYPE_INVALID);
1052}
1053
1054static DBusMessage *list_proxies(DBusConnection *conn,
1055				DBusMessage *msg, void *data)
1056{
1057	struct serial_adapter *adapter = data;
1058	const GSList *l;
1059	DBusMessage *reply;
1060	DBusMessageIter iter, iter_array;
1061
1062	reply = dbus_message_new_method_return(msg);
1063	if (!reply)
1064		return NULL;
1065
1066	dbus_message_iter_init_append(reply, &iter);
1067	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1068			DBUS_TYPE_STRING_AS_STRING, &iter_array);
1069
1070	for (l = adapter->proxies; l; l = l->next) {
1071		struct serial_proxy *prx = l->data;
1072
1073		dbus_message_iter_append_basic(&iter_array,
1074				DBUS_TYPE_STRING, &prx->path);
1075	}
1076
1077	dbus_message_iter_close_container(&iter, &iter_array);
1078
1079	return reply;
1080}
1081
1082static DBusMessage *remove_proxy(DBusConnection *conn,
1083				DBusMessage *msg, void *data)
1084{
1085	struct serial_adapter *adapter = data;
1086	struct serial_proxy *prx;
1087	const char *path, *sender;
1088	GSList *l;
1089
1090	if (!dbus_message_get_args(msg, NULL,
1091				DBUS_TYPE_STRING, &path,
1092				DBUS_TYPE_INVALID))
1093		return NULL;
1094
1095	l = g_slist_find_custom(adapter->proxies, path, proxy_pathcmp);
1096	if (!l)
1097		return btd_error_does_not_exist(msg);
1098
1099	prx = l->data;
1100
1101	sender = dbus_message_get_sender(msg);
1102	if (g_strcmp0(prx->owner, sender) != 0)
1103		return btd_error_not_authorized(msg);
1104
1105	unregister_proxy(prx);
1106
1107	return dbus_message_new_method_return(msg);
1108}
1109
1110static void manager_path_unregister(void *data)
1111{
1112	struct serial_adapter *adapter = data;
1113	GSList *l;
1114
1115	/* Remove proxy objects */
1116	for (l = adapter->proxies; l; l = l->next) {
1117		struct serial_proxy *prx = l->data;
1118		char *path = g_strdup(prx->path);
1119
1120		g_dbus_unregister_interface(adapter->conn, path,
1121					SERIAL_PROXY_INTERFACE);
1122		g_free(path);
1123	}
1124
1125	if (adapter->conn)
1126		dbus_connection_unref(adapter->conn);
1127
1128	adapters = g_slist_remove(adapters, adapter);
1129	g_slist_free(adapter->proxies);
1130	btd_adapter_unref(adapter->btd_adapter);
1131	g_free(adapter);
1132}
1133
1134static GDBusMethodTable manager_methods[] = {
1135	{ "CreateProxy",		"ss",	"s",	create_proxy },
1136	{ "ListProxies",		"",	"as",	list_proxies },
1137	{ "RemoveProxy",		"s",	"",	remove_proxy },
1138	{ },
1139};
1140
1141static GDBusSignalTable manager_signals[] = {
1142	{ "ProxyCreated",		"s"	},
1143	{ "ProxyRemoved",		"s"	},
1144	{ }
1145};
1146
1147static struct serial_adapter *find_adapter(GSList *list,
1148					struct btd_adapter *btd_adapter)
1149{
1150	for (; list; list = list->next) {
1151		struct serial_adapter *adapter = list->data;
1152
1153		if (adapter->btd_adapter == btd_adapter)
1154			return adapter;
1155	}
1156
1157	return NULL;
1158}
1159
1160static void serial_proxy_init(struct serial_adapter *adapter)
1161{
1162	GKeyFile *config;
1163	GError *gerr = NULL;
1164	const char *file = CONFIGDIR "/serial.conf";
1165	char **group_list;
1166	int i;
1167
1168	config = g_key_file_new();
1169
1170	if (!g_key_file_load_from_file(config, file, 0, &gerr)) {
1171		error("Parsing %s failed: %s", file, gerr->message);
1172		g_error_free(gerr);
1173		g_key_file_free(config);
1174		return;
1175	}
1176
1177	group_list = g_key_file_get_groups(config, NULL);
1178
1179	for (i = 0; group_list[i] != NULL; i++) {
1180		char *group_str = group_list[i], *uuid_str, *address;
1181		int err;
1182		struct serial_proxy *prx;
1183
1184		/* string length of "Proxy" is 5 */
1185		if (strlen(group_str) < 5 || strncmp(group_str, "Proxy", 5))
1186			continue;
1187
1188		uuid_str = g_key_file_get_string(config, group_str, "UUID",
1189									&gerr);
1190		if (gerr) {
1191			DBG("%s: %s", file, gerr->message);
1192			g_error_free(gerr);
1193			g_key_file_free(config);
1194			g_strfreev(group_list);
1195			return;
1196		}
1197
1198		address = g_key_file_get_string(config, group_str, "Address",
1199									&gerr);
1200		if (gerr) {
1201			DBG("%s: %s", file, gerr->message);
1202			g_error_free(gerr);
1203			g_key_file_free(config);
1204			g_free(uuid_str);
1205			g_strfreev(group_list);
1206			return;
1207		}
1208
1209		err = register_proxy(adapter, uuid_str, address, &prx);
1210		if (err == -EINVAL)
1211			error("Invalid address.");
1212		else if (err == -EALREADY)
1213			DBG("Proxy already exists.");
1214		else if (err < 0)
1215			error("Proxy creation failed (%s)", strerror(-err));
1216		else {
1217			err = enable_proxy(prx);
1218			if (err < 0)
1219				error("Proxy enable failed (%s)",
1220						strerror(-err));
1221		}
1222
1223		g_free(uuid_str);
1224		g_free(address);
1225	}
1226
1227	g_strfreev(group_list);
1228	g_key_file_free(config);
1229}
1230
1231int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
1232{
1233	struct serial_adapter *adapter;
1234	const char *path;
1235
1236	adapter = find_adapter(adapters, btd_adapter);
1237	if (adapter)
1238		return -EINVAL;
1239
1240	adapter = g_new0(struct serial_adapter, 1);
1241	adapter->conn = dbus_connection_ref(conn);
1242	adapter->btd_adapter = btd_adapter_ref(btd_adapter);
1243
1244	path = adapter_get_path(btd_adapter);
1245
1246	if (!g_dbus_register_interface(conn, path,
1247					SERIAL_MANAGER_INTERFACE,
1248					manager_methods, manager_signals, NULL,
1249					adapter, manager_path_unregister)) {
1250		error("Failed to register %s interface to %s",
1251				SERIAL_MANAGER_INTERFACE, path);
1252		return -1;
1253	}
1254
1255	adapters = g_slist_append(adapters, adapter);
1256
1257	DBG("Registered interface %s on path %s",
1258		SERIAL_MANAGER_INTERFACE, path);
1259
1260	serial_proxy_init(adapter);
1261
1262	return 0;
1263}
1264
1265void proxy_unregister(struct btd_adapter *btd_adapter)
1266{
1267	struct serial_adapter *adapter;
1268
1269	adapter = find_adapter(adapters, btd_adapter);
1270	if (!adapter)
1271		return;
1272
1273	g_dbus_unregister_interface(adapter->conn,
1274			adapter_get_path(btd_adapter),
1275			SERIAL_MANAGER_INTERFACE);
1276}
1277