~bluetooth/bluez/vivid-phone-overlay

« back to all changes in this revision

Viewing changes to .pc/hid-reconnect-mode.patch/input/server.c

  • Committer: Simon Fels
  • Date: 2015-09-11 09:01:46 UTC
  • Revision ID: morphis@gravedo.de-20150911090146-4c0ln9s7ec3xf0nx
Import package bluez_4.101-0ubuntu25.1~overlay4 from stable phone overlay PPA

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <unistd.h>
 
29
#include <errno.h>
 
30
 
 
31
#include <bluetooth/bluetooth.h>
 
32
#include <bluetooth/sdp.h>
 
33
#include <bluetooth/uuid.h>
 
34
 
 
35
#include <glib.h>
 
36
#include <dbus/dbus.h>
 
37
 
 
38
#include "log.h"
 
39
 
 
40
#include "glib-helper.h"
 
41
#include "btio.h"
 
42
#include "adapter.h"
 
43
#include "device.h"
 
44
#include "server.h"
 
45
 
 
46
static GSList *servers = NULL;
 
47
struct input_server {
 
48
        bdaddr_t src;
 
49
        GIOChannel *ctrl;
 
50
        GIOChannel *intr;
 
51
        GIOChannel *confirm;
 
52
};
 
53
 
 
54
static gint server_cmp(gconstpointer s, gconstpointer user_data)
 
55
{
 
56
        const struct input_server *server = s;
 
57
        const bdaddr_t *src = user_data;
 
58
 
 
59
        return bacmp(&server->src, src);
 
60
}
 
61
 
 
62
static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
 
63
{
 
64
        uint16_t psm;
 
65
        bdaddr_t src, dst;
 
66
        char address[18];
 
67
        GError *gerr = NULL;
 
68
        int ret;
 
69
 
 
70
        if (err) {
 
71
                error("%s", err->message);
 
72
                return;
 
73
        }
 
74
 
 
75
        bt_io_get(chan, BT_IO_L2CAP, &gerr,
 
76
                        BT_IO_OPT_SOURCE_BDADDR, &src,
 
77
                        BT_IO_OPT_DEST_BDADDR, &dst,
 
78
                        BT_IO_OPT_PSM, &psm,
 
79
                        BT_IO_OPT_INVALID);
 
80
        if (gerr) {
 
81
                error("%s", gerr->message);
 
82
                g_error_free(gerr);
 
83
                g_io_channel_shutdown(chan, TRUE, NULL);
 
84
                return;
 
85
        }
 
86
 
 
87
        ba2str(&dst, address);
 
88
        DBG("Incoming connection from %s on PSM %d", address, psm);
 
89
 
 
90
        ret = input_device_set_channel(&src, &dst, psm, chan);
 
91
        if (ret == 0)
 
92
                return;
 
93
 
 
94
        error("Refusing input device connect: %s (%d)", strerror(-ret), -ret);
 
95
 
 
96
        /* Send unplug virtual cable to unknown devices */
 
97
        if (ret == -ENOENT && psm == L2CAP_PSM_HIDP_CTRL) {
 
98
                unsigned char unplug = 0x15;
 
99
                int sk = g_io_channel_unix_get_fd(chan);
 
100
                if (write(sk, &unplug, sizeof(unplug)) < 0)
 
101
                        error("Unable to send virtual cable unplug");
 
102
        }
 
103
 
 
104
        g_io_channel_shutdown(chan, TRUE, NULL);
 
105
}
 
106
 
 
107
static void auth_callback(DBusError *derr, void *user_data)
 
108
{
 
109
        struct input_server *server = user_data;
 
110
        bdaddr_t src, dst;
 
111
        GError *err = NULL;
 
112
 
 
113
        bt_io_get(server->confirm, BT_IO_L2CAP, &err,
 
114
                        BT_IO_OPT_SOURCE_BDADDR, &src,
 
115
                        BT_IO_OPT_DEST_BDADDR, &dst,
 
116
                        BT_IO_OPT_INVALID);
 
117
        if (err) {
 
118
                error("%s", err->message);
 
119
                g_error_free(err);
 
120
                goto reject;
 
121
        }
 
122
 
 
123
        if (derr) {
 
124
                error("Access denied: %s", derr->message);
 
125
                goto reject;
 
126
        }
 
127
 
 
128
        if (!bt_io_accept(server->confirm, connect_event_cb, server,
 
129
                                NULL, &err)) {
 
130
                error("bt_io_accept: %s", err->message);
 
131
                g_error_free(err);
 
132
                goto reject;
 
133
        }
 
134
 
 
135
        g_io_channel_unref(server->confirm);
 
136
        server->confirm = NULL;
 
137
 
 
138
        return;
 
139
 
 
140
reject:
 
141
        g_io_channel_shutdown(server->confirm, TRUE, NULL);
 
142
        g_io_channel_unref(server->confirm);
 
143
        server->confirm = NULL;
 
144
        input_device_close_channels(&src, &dst);
 
145
}
 
146
 
 
147
static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
 
148
{
 
149
        struct input_server *server = user_data;
 
150
        bdaddr_t src, dst;
 
151
        GError *err = NULL;
 
152
        char addr[18];
 
153
        int ret;
 
154
 
 
155
        bt_io_get(chan, BT_IO_L2CAP, &err,
 
156
                        BT_IO_OPT_SOURCE_BDADDR, &src,
 
157
                        BT_IO_OPT_DEST_BDADDR, &dst,
 
158
                        BT_IO_OPT_INVALID);
 
159
        if (err) {
 
160
                error("%s", err->message);
 
161
                g_error_free(err);
 
162
                goto drop;
 
163
        }
 
164
 
 
165
        if (server->confirm) {
 
166
                char address[18];
 
167
 
 
168
                ba2str(&dst, address);
 
169
                error("Refusing connection from %s: setup in progress",
 
170
                                                                address);
 
171
                goto drop;
 
172
        }
 
173
 
 
174
        server->confirm = g_io_channel_ref(chan);
 
175
 
 
176
        ret = btd_request_authorization(&src, &dst, HID_UUID,
 
177
                                        auth_callback, server);
 
178
        if (ret == 0)
 
179
                return;
 
180
 
 
181
        ba2str(&src, addr);
 
182
        error("input: authorization for %s failed: %s (%d)",
 
183
                                                addr, strerror(-ret), ret);
 
184
 
 
185
        g_io_channel_unref(server->confirm);
 
186
        server->confirm = NULL;
 
187
 
 
188
drop:
 
189
        input_device_close_channels(&src, &dst);
 
190
        g_io_channel_shutdown(chan, TRUE, NULL);
 
191
}
 
192
 
 
193
int server_start(const bdaddr_t *src)
 
194
{
 
195
        struct input_server *server;
 
196
        GError *err = NULL;
 
197
 
 
198
        server = g_new0(struct input_server, 1);
 
199
        bacpy(&server->src, src);
 
200
 
 
201
        server->ctrl = bt_io_listen(BT_IO_L2CAP, connect_event_cb, NULL,
 
202
                                server, NULL, &err,
 
203
                                BT_IO_OPT_SOURCE_BDADDR, src,
 
204
                                BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
 
205
                                BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 
206
                                BT_IO_OPT_INVALID);
 
207
        if (!server->ctrl) {
 
208
                error("Failed to listen on control channel");
 
209
                g_error_free(err);
 
210
                g_free(server);
 
211
                return -1;
 
212
        }
 
213
 
 
214
        server->intr = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event_cb,
 
215
                                server, NULL, &err,
 
216
                                BT_IO_OPT_SOURCE_BDADDR, src,
 
217
                                BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
 
218
                                BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
 
219
                                BT_IO_OPT_INVALID);
 
220
        if (!server->intr) {
 
221
                error("Failed to listen on interrupt channel");
 
222
                g_io_channel_unref(server->ctrl);
 
223
                g_error_free(err);
 
224
                g_free(server);
 
225
                return -1;
 
226
        }
 
227
 
 
228
        servers = g_slist_append(servers, server);
 
229
 
 
230
        return 0;
 
231
}
 
232
 
 
233
void server_stop(const bdaddr_t *src)
 
234
{
 
235
        struct input_server *server;
 
236
        GSList *l;
 
237
 
 
238
        l = g_slist_find_custom(servers, src, server_cmp);
 
239
        if (!l)
 
240
                return;
 
241
 
 
242
        server = l->data;
 
243
 
 
244
        g_io_channel_shutdown(server->intr, TRUE, NULL);
 
245
        g_io_channel_unref(server->intr);
 
246
 
 
247
        g_io_channel_shutdown(server->ctrl, TRUE, NULL);
 
248
        g_io_channel_unref(server->ctrl);
 
249
 
 
250
        servers = g_slist_remove(servers, server);
 
251
        g_free(server);
 
252
}