11202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg/*
21202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
31202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  BlueZ - Bluetooth protocol stack for Linux
41202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
51202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  Copyright (C) 2010  Nokia Corporation
61202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
71202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
81202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
91202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  This program is free software; you can redistribute it and/or modify
101202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  it under the terms of the GNU General Public License as published by
111202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  the Free Software Foundation; either version 2 of the License, or
121202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  (at your option) any later version.
131202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
141202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  This program is distributed in the hope that it will be useful,
151202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  but WITHOUT ANY WARRANTY; without even the implied warranty of
161202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
171202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  GNU General Public License for more details.
181202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
191202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  You should have received a copy of the GNU General Public License
201202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  along with this program; if not, write to the Free Software
211202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
221202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg *
231202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg */
241202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
251202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#ifdef HAVE_CONFIG_H
261202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <config.h>
271202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#endif
281202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
291202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <errno.h>
301202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <unistd.h>
311202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <sys/socket.h>
32895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#include <sys/ioctl.h>
33895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#include <sys/types.h>
34895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#include <sys/stat.h>
35895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#include <sys/wait.h>
36895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#include <fcntl.h>
371202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
381202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <bluetooth/bluetooth.h>
391202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <bluetooth/rfcomm.h>
401202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <bluetooth/sdp.h>
411202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <bluetooth/sdp_lib.h>
421202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
431202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <glib.h>
441202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
451202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include <gdbus.h>
461202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
471202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include "plugin.h"
481202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include "sdpd.h"
491202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include "btio.h"
501202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#include "adapter.h"
51e891f7df6225c758da0d95f7554c6cc67f72f31eGustavo F. Padovan#include "log.h"
521202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
53895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg/* FIXME: This location should be build-time configurable */
5429598cc39b9cb63d7ed62fb2b7f99c9c42985897Johan Hedberg#define PNATD "/usr/bin/phonet-at"
55895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
561202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#define DUN_CHANNEL 1
571202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg#define DUN_UUID "00001103-0000-1000-8000-00805F9B34FB"
581202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
59895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#define TTY_TIMEOUT 100
60895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg#define TTY_TRIES 10
61895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
62895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstruct dun_client {
63895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bdaddr_t bda;
64895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
65895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	GIOChannel *io;	/* Client socket */
66895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	guint io_watch;	/* Client IO watch id */
67895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
68895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	guint tty_timer;
69895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	int tty_tries;
70895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	gboolean tty_open;
71895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	int tty_id;
72895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	char tty_name[PATH_MAX];
73895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
74895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	GPid pnatd_pid;
75895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	guint pnatd_watch;
76895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg};
77895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
781202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstruct dun_server {
79895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bdaddr_t bda;		/* Local adapter address */
80895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
811202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	uint32_t record_handle; /* Local SDP record handle */
821202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GIOChannel *server;	/* Server socket */
83895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
84895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	int rfcomm_ctl;
85895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
86895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client client;
871202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg};
881202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
891202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic GSList *servers = NULL;
901202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
911202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void disconnect(struct dun_server *server)
921202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
93895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
94895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
95895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (!client->io)
96895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		return;
97895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
98895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	g_io_channel_unref(client->io);
99895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io = NULL;
100895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
101895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->io_watch > 0) {
102895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		g_source_remove(client->io_watch);
103895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->io_watch = 0;
104895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
105895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
106895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->pnatd_watch > 0) {
107895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		g_source_remove(client->pnatd_watch);
108895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->pnatd_watch = 0;
109895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		if (client->pnatd_pid > 0)
110895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			kill(client->pnatd_pid, SIGTERM);
111895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
112895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
113895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->pnatd_pid > 0) {
114895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		g_spawn_close_pid(client->pnatd_pid);
115895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->pnatd_pid = 0;
116895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
117895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
118895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->tty_timer > 0) {
119895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		g_source_remove(client->tty_timer);
120895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_timer = 0;
121895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
122895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
123895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->tty_id >= 0) {
124895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		struct rfcomm_dev_req req;
125895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
126895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		memset(&req, 0, sizeof(req));
127895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		req.dev_id = client->tty_id;
128895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		req.flags = (1 << RFCOMM_HANGUP_NOW);
129895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		ioctl(server->rfcomm_ctl, RFCOMMRELEASEDEV, &req);
130895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
131895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_name[0] = '\0';
132895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_open = FALSE;
133895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_id = -1;
134895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
1351202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
1361202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
137895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstatic gboolean client_event(GIOChannel *chan,
1381202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg					GIOCondition cond, gpointer data)
1391202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
1401202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server = data;
141895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
142895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	char addr[18];
1431202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
144895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	ba2str(&client->bda, addr);
1451202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
1468e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan	DBG("Disconnected DUN from %s (%s)", addr, client->tty_name);
147895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
148895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io_watch = 0;
149895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	disconnect(server);
1501202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
151895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	return FALSE;
152895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg}
153895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
154895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstatic void pnatd_exit(GPid pid, gint status, gpointer user_data)
155895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg{
156895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_server *server = user_data;
157895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
158895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
159895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg        if (WIFEXITED(status))
1608e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan                DBG("pnatd (%d) exited with status %d", pid,
161895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg							WEXITSTATUS(status));
162895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg        else
1638e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan                DBG("pnatd (%d) was killed by signal %d", pid,
164895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg							WTERMSIG(status));
165895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
166895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->pnatd_watch = 0;
167895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
168895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	disconnect(server);
169895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg}
170895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
171895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstatic gboolean start_pnatd(struct dun_server *server)
172895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg{
173895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
174895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
175895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	char *argv[] = { PNATD, client->tty_name, NULL };
176895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	GError *err = NULL;
177895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	GPid pid;
178895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
179895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, &pid, &err);
180895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (err != NULL) {
181895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		error("Unable to spawn pnatd: %s", err->message);
18276208a5d2612081517846692bb6b8f99c4059fcaJohan Hedberg		g_error_free(err);
183895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		return FALSE;
184895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
185895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
1868e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan	DBG("pnatd started for %s with pid %d", client->tty_name, pid);
187895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
188895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->pnatd_pid = pid;
189895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->pnatd_watch = g_child_watch_add(pid, pnatd_exit, server);
1901202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
1911202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return TRUE;
192895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg}
1931202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
194895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstatic gboolean tty_try_open(gpointer user_data)
195895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg{
196895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_server *server = user_data;
197895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
198895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	int tty_fd;
199895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
200895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	tty_fd = open(client->tty_name, O_RDONLY | O_NOCTTY);
201895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (tty_fd < 0) {
202895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		if (errno == EACCES)
203895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			goto disconnect;
204895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
205895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_tries--;
206895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
207895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		if (client->tty_tries <= 0)
208895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			goto disconnect;
209895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
210895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		return TRUE;
211895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
212895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
2138e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan	DBG("%s created for DUN", client->tty_name);
214895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
215895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->tty_open = TRUE;
216895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->tty_timer = 0;
217895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
218895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	g_io_channel_unref(client->io);
219895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	g_source_remove(client->io_watch);
220895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
221895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io = g_io_channel_unix_new(tty_fd);
222895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io_watch = g_io_add_watch(client->io,
223895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
224895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg					client_event, server);
225895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
226895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (!start_pnatd(server))
227895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		goto disconnect;
228895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
229895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	return FALSE;
230895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
231895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergdisconnect:
232895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->tty_timer = 0;
2331202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	disconnect(server);
2341202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return FALSE;
2351202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
2361202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
237895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedbergstatic gboolean create_tty(struct dun_server *server)
238895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg{
239895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
240895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct rfcomm_dev_req req;
241895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	int dev, sk = g_io_channel_unix_get_fd(client->io);
242895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
243895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	memset(&req, 0, sizeof(req));
244895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	req.dev_id = -1;
245895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
246895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
247895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bacpy(&req.src, &server->bda);
248895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bacpy(&req.dst, &client->bda);
249895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
250895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bt_io_get(client->io, BT_IO_RFCOMM, NULL,
251895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			BT_IO_OPT_DEST_CHANNEL, &req.channel,
252895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			BT_IO_OPT_INVALID);
253895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
254895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	dev = ioctl(sk, RFCOMMCREATEDEV, &req);
255895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (dev < 0) {
256895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		error("Can't create RFCOMM TTY: %s", strerror(errno));
257895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		return FALSE;
258895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
259895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
260895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	snprintf(client->tty_name, PATH_MAX - 1, "/dev/rfcomm%d", dev);
261895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
262895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->tty_tries = TTY_TRIES;
263895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
264895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	tty_try_open(server);
265895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (!client->tty_open && client->tty_tries > 0)
266895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		client->tty_timer = g_timeout_add(TTY_TIMEOUT,
267895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg							tty_try_open, server);
268895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
269895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	return TRUE;
270895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg}
271895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
2721202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
2731202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
2741202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server = user_data;
2751202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
2761202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (err) {
2771202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Accepting DUN connection failed: %s", err->message);
2781202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		disconnect(server);
2791202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return;
2801202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
2811202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
282895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (!create_tty(server)) {
283895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		error("Device creation failed");
284895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		disconnect(server);
285895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
2861202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
2871202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
2881202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void auth_cb(DBusError *derr, void *user_data)
2891202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
2901202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server = user_data;
291895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
2921202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GError *err = NULL;
2931202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
2941202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (derr && dbus_error_is_set(derr)) {
2951202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("DUN access denied: %s", derr->message);
2961202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		goto drop;
2971202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
2981202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
299895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (!bt_io_accept(client->io, connect_cb, server, NULL, &err)) {
3001202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("bt_io_accept: %s", err->message);
3011202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		g_error_free(err);
3021202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		goto drop;
3031202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
3041202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3051202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return;
3061202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3071202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergdrop:
3081202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	disconnect(server);
3091202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
3101202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3111202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic gboolean auth_watch(GIOChannel *chan, GIOCondition cond, gpointer data)
3121202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
3131202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server = data;
314895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
3151202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3161202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	error("DUN client disconnected while waiting for authorization");
3171202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
318895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	btd_cancel_authorization(&server->bda, &client->bda);
3191202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3201202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	disconnect(server);
3211202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3221202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return FALSE;
3231202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
3241202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3251202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void confirm_cb(GIOChannel *io, gpointer user_data)
3261202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
3271202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server = user_data;
328895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	struct dun_client *client = &server->client;
3291202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GError *err = NULL;
3301202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
331895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (client->io) {
3321202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Rejecting DUN connection since one already exists");
3331202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return;
3341202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
3351202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3361202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	bt_io_get(io, BT_IO_RFCOMM, &err,
337895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg			BT_IO_OPT_DEST_BDADDR, &client->bda,
3381202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg			BT_IO_OPT_INVALID);
3391202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (err != NULL) {
3401202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Unable to get DUN source and dest address: %s",
3411202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg								err->message);
3421202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		g_error_free(err);
3431202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return;
3441202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
3451202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
346895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (btd_request_authorization(&server->bda, &client->bda, DUN_UUID,
3471202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg						auth_cb, user_data) < 0) {
3481202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Requesting DUN authorization failed");
3491202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return;
3501202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
3511202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
352895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io_watch = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
3531202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg						(GIOFunc) auth_watch, server);
354895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	client->io = g_io_channel_ref(io);
3551202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
3561202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3571202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic sdp_record_t *dun_record(uint8_t ch)
3581202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
3591202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
3601202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	uuid_t root_uuid, dun, gn, l2cap, rfcomm;
3611202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_profile_desc_t profile;
3621202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_t *proto[2];
3631202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_record_t *record;
3641202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_data_t *channel;
3651202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3661202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	record = sdp_record_alloc();
3671202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (!record)
3681202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return NULL;
3691202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3701202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
3711202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	root = sdp_list_append(NULL, &root_uuid);
3721202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_set_browse_groups(record, root);
3731202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3741202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
3751202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	svclass_id = sdp_list_append(NULL, &dun);
3761202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&gn,  GENERIC_NETWORKING_SVCLASS_ID);
3771202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	svclass_id = sdp_list_append(svclass_id, &gn);
3781202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_set_service_classes(record, svclass_id);
3791202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3801202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
3811202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	profile.version = 0x0100;
3821202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	pfseq = sdp_list_append(NULL, &profile);
3831202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_set_profile_descs(record, pfseq);
3841202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3851202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&l2cap, L2CAP_UUID);
3861202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	proto[0] = sdp_list_append(NULL, &l2cap);
3871202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	apseq = sdp_list_append(NULL, proto[0]);
3881202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3891202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
3901202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	proto[1] = sdp_list_append(NULL, &rfcomm);
3911202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	channel = sdp_data_alloc(SDP_UINT8, &ch);
3921202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	proto[1] = sdp_list_append(proto[1], channel);
3931202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	apseq = sdp_list_append(apseq, proto[1]);
3941202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3951202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	aproto = sdp_list_append(0, apseq);
3961202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_set_access_protos(record, aproto);
3971202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
3981202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_set_info_attr(record, "Dial-Up Networking", 0, 0);
3991202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4001202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_data_free(channel);
4011202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(root, NULL);
4021202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(svclass_id, NULL);
4031202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(proto[0], NULL);
4041202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(proto[1], NULL);
4051202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(pfseq, NULL);
4061202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(apseq, NULL);
4071202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_list_free(aproto, NULL);
4081202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4091202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return record;
4101202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
4111202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4121202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic gint server_cmp(gconstpointer a, gconstpointer b)
4131202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
4141202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	const struct dun_server *server = a;
4151202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	const bdaddr_t *src = b;
4161202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
417895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	return bacmp(src, &server->bda);
4181202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
4191202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4201202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic int pnat_probe(struct btd_adapter *adapter)
4211202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
4221202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server;
4231202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GIOChannel *io;
4241202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GError *err = NULL;
4251202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	sdp_record_t *record;
4261202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	bdaddr_t src;
4271202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4281202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	adapter_get_address(adapter, &src);
4291202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4301202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	server = g_new0(struct dun_server, 1);
4311202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4321202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_cb, server, NULL, &err,
4331202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg				BT_IO_OPT_SOURCE_BDADDR, &src,
4341202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg				BT_IO_OPT_CHANNEL, DUN_CHANNEL,
4351202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg				BT_IO_OPT_INVALID);
4361202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (err != NULL) {
4371202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Failed to start DUN server: %s", err->message);
4381202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		g_error_free(err);
439903804a0f1d74b324182b33fbc5a4d57da959e83Johan Hedberg		goto fail;
4401202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
4411202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4421202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	record = dun_record(DUN_CHANNEL);
4431202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (!record) {
4441202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Unable to allocate new service record");
4451202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		goto fail;
4461202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
4471202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4481202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (add_record_to_server(&src, record) < 0) {
4491202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		error("Unable to register DUN service record");
4501202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		goto fail;
4511202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	}
4521202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
453895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	server->rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
454895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	if (server->rfcomm_ctl < 0) {
455895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		error("Unable to create RFCOMM control socket: %s (%d)",
456895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg						strerror(errno), errno);
457895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg		goto fail;
458895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	}
459895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg
4601202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	server->server = io;
4611202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	server->record_handle = record->handle;
462895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	bacpy(&server->bda, &src);
4631202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4641202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	servers = g_slist_append(servers, server);
4651202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4661202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return 0;
4671202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4681202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergfail:
4691202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (io != NULL)
4701202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		g_io_channel_unref(io);
4711202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	g_free(server);
4721202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return -EIO;
4731202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
4741202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4751202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void pnat_remove(struct btd_adapter *adapter)
4761202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
4771202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	struct dun_server *server;
4781202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	GSList *match;
4791202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	bdaddr_t src;
4801202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4811202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	adapter_get_address(adapter, &src);
4821202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4831202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	match = g_slist_find_custom(servers, &src, server_cmp);
4841202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	if (match == NULL)
4851202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg		return;
4861202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4871202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	server = match->data;
4881202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4891202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	servers = g_slist_delete_link(servers, match);
4901202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
491895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	disconnect(server);
4921202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
4931202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	remove_record_from_server(server->record_handle);
494895eea1347243bae4aa65eea8531452fe5dd81eaJohan Hedberg	close(server->rfcomm_ctl);
4951202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	g_io_channel_shutdown(server->server, TRUE, NULL);
4961202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	g_io_channel_unref(server->server);
4971202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	g_free(server);
4981202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
4991202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5001202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic struct btd_adapter_driver pnat_server = {
5011202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	.name	= "pnat-server",
5021202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	.probe	= pnat_probe,
5031202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	.remove	= pnat_remove,
5041202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg};
5051202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5061202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic int pnat_init(void)
5071202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
5088e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan	DBG("Setup Phonet AT (DUN) plugin");
5091202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5101202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	return btd_register_adapter_driver(&pnat_server);
5111202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
5121202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5131202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedbergstatic void pnat_exit(void)
5141202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg{
5158e58667ef0a4cda88ac64137728da28d8fdf3f0fGustavo F. Padovan	DBG("Cleanup Phonet AT (DUN) plugin");
5161202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5171202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg	btd_unregister_adapter_driver(&pnat_server);
5181202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg}
5191202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg
5201202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan HedbergBLUETOOTH_PLUGIN_DEFINE(pnat, VERSION,
5211202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg			BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
5221202ec1f3e2e23ed3f343bedbc7ca86377030c2cJohan Hedberg			pnat_init, pnat_exit)
523