server.c revision 9491a544f622e40453265c30f24ce44a61440cc1
1/* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2008 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 <errno.h> 29#include <unistd.h> 30#include <stdlib.h> 31#include <sys/ioctl.h> 32#include <sys/socket.h> 33 34#include <bluetooth/bluetooth.h> 35#include <bluetooth/l2cap.h> 36#include <bluetooth/hidp.h> 37#include <bluetooth/hci.h> 38#include <bluetooth/hci_lib.h> 39 40#include <glib.h> 41 42#include "logging.h" 43#include "dbus.h" 44 45#include "device.h" 46#include "server.h" 47#include "storage.h" 48#include "dbus-service.h" 49 50static const char* HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"; 51 52static DBusConnection *connection = NULL; 53 54static void cancel_authorization(const char *addr) 55{ 56 DBusMessage *msg; 57 58 msg = dbus_message_new_method_call("org.bluez", "/org/bluez", 59 "org.bluez.Database", 60 "CancelAuthorizationRequest"); 61 if (!msg) { 62 error("Unable to allocate new method call"); 63 return; 64 } 65 66 dbus_message_append_args(msg, 67 DBUS_TYPE_STRING, &addr, 68 DBUS_TYPE_STRING, &HID_UUID, 69 DBUS_TYPE_INVALID); 70 71 send_message_and_unref(connection, msg); 72} 73 74struct authorization_data { 75 bdaddr_t src; 76 bdaddr_t dst; 77}; 78 79static void authorization_callback(DBusPendingCall *pcall, void *data) 80{ 81 struct authorization_data *auth = data; 82 DBusMessage *reply = dbus_pending_call_steal_reply(pcall); 83 DBusError derr; 84 85 dbus_error_init(&derr); 86 if (dbus_set_error_from_message(&derr, reply) != TRUE) { 87 dbus_message_unref(reply); 88 input_device_connadd(&auth->src, &auth->dst); 89 return; 90 } 91 92 error("Authorization denied: %s", derr.message); 93 if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) { 94 char addr[18]; 95 memset(addr, 0, sizeof(addr)); 96 ba2str(&auth->dst, addr); 97 cancel_authorization(addr); 98 } 99 100 input_device_close_channels(&auth->src, &auth->dst); 101 102 dbus_error_free(&derr); 103 dbus_message_unref(reply); 104} 105 106static void auth_callback(DBusError *derr, void *user_data) 107{ 108 struct authorization_data *auth = user_data; 109 110 if (derr) { 111 error("Access denied: %s", derr->message); 112 if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY)) 113 service_cancel_auth(&auth->dst); 114 115 input_device_close_channels(&auth->src, &auth->dst); 116 } else 117 input_device_connadd(&auth->src, &auth->dst); 118 119 g_free(auth); 120} 121 122static int authorize_device(bdaddr_t *src, bdaddr_t *dst) 123{ 124 struct authorization_data *auth; 125 DBusMessage *msg; 126 DBusPendingCall *pending; 127 char addr[18]; 128 const char *paddr = addr; 129 int retval; 130 131 auth = g_new0(struct authorization_data, 1); 132 bacpy(&auth->src, src); 133 bacpy(&auth->dst, dst); 134 135 retval = service_req_auth(src, dst, HID_UUID, 136 auth_callback, auth); 137 if (retval < 0) 138 goto fallback; 139 140 return retval; 141 142fallback: 143 msg = dbus_message_new_method_call("org.bluez", "/org/bluez", 144 "org.bluez.Database", "RequestAuthorization"); 145 if (!msg) { 146 error("Unable to allocate new RequestAuthorization method call"); 147 return -ENOMEM; 148 } 149 150 memset(addr, 0, sizeof(addr)); 151 ba2str(dst, addr); 152 dbus_message_append_args(msg, 153 DBUS_TYPE_STRING, &paddr, 154 DBUS_TYPE_STRING, &HID_UUID, 155 DBUS_TYPE_INVALID); 156 157 if (dbus_connection_send_with_reply(connection, 158 msg, &pending, -1) == FALSE) 159 return -EACCES; 160 161 dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free); 162 dbus_pending_call_unref(pending); 163 dbus_message_unref(msg); 164 165 return 0; 166} 167 168static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data) 169{ 170 struct sockaddr_l2 addr; 171 socklen_t addrlen; 172 bdaddr_t src, dst; 173 unsigned char psm; 174 int sk, nsk; 175 176 sk = g_io_channel_unix_get_fd(chan); 177 178 memset(&addr, 0, sizeof(addr)); 179 addrlen = sizeof(addr); 180 181 nsk = accept(sk, (struct sockaddr *) &addr, &addrlen); 182 if (nsk < 0) 183 return TRUE; 184 185 bacpy(&dst, &addr.l2_bdaddr); 186 psm = btohs(addr.l2_psm); 187 188 memset(&addr, 0, sizeof(addr)); 189 addrlen = sizeof(addr); 190 191 if (getsockname(nsk, (struct sockaddr *) &addr, &addrlen) < 0) { 192 close(nsk); 193 return TRUE; 194 } 195 196 bacpy(&src, &addr.l2_bdaddr); 197 198 debug("Incoming connection on PSM %d", psm); 199 200 if (input_device_set_channel(&src, &dst, psm, nsk) < 0) { 201 /* Send unplug virtual cable to unknown devices */ 202 if (psm == L2CAP_PSM_HIDP_CTRL) { 203 unsigned char unplug[] = { 0x15 }; 204 int err; 205 err = write(nsk, unplug, sizeof(unplug)); 206 } 207 close(nsk); 208 return TRUE; 209 } 210 211 if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0)) 212 input_device_close_channels(&src, &dst); 213 214 return TRUE; 215} 216 217static GIOChannel *setup_l2cap(unsigned int psm) 218{ 219 GIOChannel *io; 220 struct sockaddr_l2 addr; 221 int sk; 222 223 sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); 224 if (sk < 0) 225 return NULL; 226 227 memset(&addr, 0, sizeof(addr)); 228 addr.l2_family = AF_BLUETOOTH; 229 bacpy(&addr.l2_bdaddr, BDADDR_ANY); 230 addr.l2_psm = htobs(psm); 231 232 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 233 close(sk); 234 return NULL; 235 } 236 237 if (listen(sk, 10) < 0) { 238 close(sk); 239 return NULL; 240 } 241 242 io = g_io_channel_unix_new(sk); 243 g_io_channel_set_close_on_unref(io, TRUE); 244 245 g_io_add_watch(io, G_IO_IN, connect_event, NULL); 246 247 return io; 248} 249 250static GIOChannel *ctrl_io = NULL; 251static GIOChannel *intr_io = NULL; 252 253int server_start(DBusConnection *conn) 254{ 255 ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL); 256 if (!ctrl_io) { 257 error("Failed to listen on control channel"); 258 return -1; 259 } 260 g_io_channel_set_close_on_unref(ctrl_io, TRUE); 261 262 intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR); 263 if (!intr_io) { 264 error("Failed to listen on interrupt channel"); 265 g_io_channel_unref(ctrl_io); 266 ctrl_io = NULL; 267 } 268 g_io_channel_set_close_on_unref(intr_io, TRUE); 269 270 connection = conn; 271 272 return 0; 273} 274 275void server_stop(void) 276{ 277 if (intr_io) 278 g_io_channel_unref(intr_io); 279 280 if (ctrl_io) 281 g_io_channel_unref(ctrl_io); 282} 283