~bluetooth/bluez/vivid-phone-overlay

« back to all changes in this revision

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

  • Committer: CI Train Bot
  • Date: 2015-09-14 10:07:45 UTC
  • mfrom: (1.1.2 add-citrain-support)
  • Revision ID: ci-train-bot@canonical.com-20150914100745-3v04zcmjdxez4lab
* debian/rules:
  - Migrate from cdbs to debhelper to make it possible to build our
    packages with the Ubuntu citrain infrastructure.

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
 
}