5 * Copyright (C) 2013 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <arpa/inet.h>
34 #define CONNMAN_API_SUBJECT_TO_CHANGE
35 #include <connman/plugin.h>
36 #include <connman/dbus.h>
37 #include <connman/technology.h>
41 #define NEARD_SERVICE "org.neard"
42 #define NEARD_PATH "/"
43 #define NEARD_MANAGER_INTERFACE "org.neard.Manager"
44 #define NEARD_AGENT_INTERFACE "org.neard.HandoverAgent"
45 #define NEARD_ERROR_INTERFACE "org.neard.HandoverAgent.Error"
47 #define AGENT_PATH "/net/connman/neard_handover_agent"
48 #define AGENT_TYPE "wifi"
50 struct data_elements {
53 gboolean fixed_length;
57 DE_AUTHENTICATION_TYPE = 0,
63 static const struct data_elements DEs[DE_MAX] = {
65 { 0x1027, 64, FALSE },
66 { 0x1045, 32, FALSE },
69 #define DE_VAL_OPEN 0x0001
70 #define DE_VAL_PSK 0x0022
73 static DBusConnection *connection = NULL;
74 DBusPendingCall *register_call = NULL;
75 gboolean agent_registered = FALSE;
76 static guint watch_id = 0;
78 static int set_2b_into_tlv(uint8_t *tlv_msg, uint16_t val)
83 ins = (uint8_t *) &ne_val;
92 static int set_byte_array_into_tlv(uint8_t *tlv_msg,
93 uint8_t *array, int length)
95 memcpy((void *)tlv_msg, (void *)array, length);
99 static uint8_t *encode_to_tlv(const char *ssid, const char *psk, int *length)
101 uint16_t ssid_len, psk_len;
105 if (ssid == NULL || length == NULL)
108 ssid_len = strlen(ssid);
110 *length = 6 + 4 + ssid_len;
112 psk_len = strlen(psk);
113 *length += 4 + psk_len;
117 tlv_msg = g_try_malloc0(sizeof(uint8_t) * (*length));
121 pos += set_2b_into_tlv(tlv_msg+pos, DEs[DE_SSID].value);
122 pos += set_2b_into_tlv(tlv_msg+pos, ssid_len);
123 pos += set_byte_array_into_tlv(tlv_msg+pos, (uint8_t *)ssid, ssid_len);
125 pos += set_2b_into_tlv(tlv_msg+pos, DEs[DE_AUTHENTICATION_TYPE].value);
126 pos += set_2b_into_tlv(tlv_msg+pos,
127 DEs[DE_AUTHENTICATION_TYPE].length);
129 pos += set_2b_into_tlv(tlv_msg+pos, DE_VAL_PSK);
130 pos += set_2b_into_tlv(tlv_msg+pos, DEs[DE_NETWORK_KEY].value);
131 pos += set_2b_into_tlv(tlv_msg+pos, psk_len);
132 pos += set_byte_array_into_tlv(tlv_msg+pos,
133 (uint8_t *)psk, psk_len);
135 pos += set_2b_into_tlv(tlv_msg+pos, DE_VAL_OPEN);
140 static int parse_request_oob_params(DBusMessage *message)
142 DBusMessageIter iter;
143 DBusMessageIter array;
145 dbus_message_iter_init(message, &iter);
147 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
150 dbus_message_iter_recurse(&iter, &array);
151 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_DICT_ENTRY)
157 static DBusMessage *create_request_oob_reply(DBusMessage *message)
160 DBusMessageIter iter;
161 DBusMessageIter dict;
162 const char *ssid, *psk;
166 if (connman_technology_get_wifi_tethering(&ssid, &psk) == FALSE)
167 return g_dbus_create_error(message,
168 NEARD_ERROR_INTERFACE ".NotSupported",
169 "Operation is not supported");
171 tlv_msg = encode_to_tlv(ssid, psk, &length);
173 return g_dbus_create_error(message,
174 NEARD_ERROR_INTERFACE ".NotSupported",
175 "Operation is not supported");
177 reply = dbus_message_new_method_return(message);
181 dbus_message_iter_init_append(reply, &iter);
183 connman_dbus_dict_open(&iter, &dict);
185 connman_dbus_dict_append_fixed_array(&dict, "WSC",
186 DBUS_TYPE_BYTE, &tlv_msg, length);
188 dbus_message_iter_close_container(&iter, &dict);
196 static DBusMessage *request_oob_method(DBusConnection *dbus_conn,
197 DBusMessage *message, void *user_data)
201 if (parse_request_oob_params(message) != 0)
202 return g_dbus_create_error(message,
203 NEARD_ERROR_INTERFACE ".Failed",
204 "Invalid parameters");
206 return create_request_oob_reply(message);
209 static DBusMessage *push_oob_method(DBusConnection *dbus_conn,
210 DBusMessage *message, void *user_data)
214 return g_dbus_create_error(message,
215 NEARD_ERROR_INTERFACE ".NotSupported",
216 "Operation is not supported");
219 static DBusMessage *release_method(DBusConnection *dbus_conn,
220 DBusMessage *message, void *user_data)
224 agent_registered = FALSE;
225 g_dbus_unregister_interface(connection,
226 AGENT_PATH, NEARD_AGENT_INTERFACE);
228 return g_dbus_create_reply(message, DBUS_TYPE_INVALID);
231 static const GDBusMethodTable neard_methods[] = {
232 { GDBUS_ASYNC_METHOD("RequestOOB",
233 GDBUS_ARGS({ "data", "a{sv}" }),
234 GDBUS_ARGS({ "data", "a{sv}" }), request_oob_method) },
235 { GDBUS_ASYNC_METHOD("PushOOB",
236 GDBUS_ARGS({ "data", "a{sv}"}), NULL, push_oob_method) },
237 { GDBUS_METHOD("Release", NULL, NULL, release_method) },
241 static void cleanup_register_call(void)
243 if (register_call != NULL) {
244 dbus_pending_call_cancel(register_call);
245 dbus_pending_call_unref(register_call);
246 register_call = NULL;
250 static void register_agent_cb(DBusPendingCall *pending, void *user_data)
254 if (dbus_pending_call_get_completed(pending) == FALSE)
257 register_call = NULL;
259 reply = dbus_pending_call_steal_reply(pending);
263 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
264 g_dbus_unregister_interface(connection,
265 AGENT_PATH, NEARD_AGENT_INTERFACE);
267 agent_registered = TRUE;
269 dbus_message_unref(reply);
271 dbus_pending_call_unref(pending);
274 static void register_agent(void)
276 const char *path = AGENT_PATH;
277 const char *type = AGENT_TYPE;
278 DBusMessage *message;
280 message = dbus_message_new_method_call(NEARD_SERVICE, NEARD_PATH,
281 NEARD_MANAGER_INTERFACE,
282 "RegisterHandoverAgent");
286 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH,
287 &path, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID);
289 if (dbus_connection_send_with_reply(connection, message,
290 ®ister_call, DBUS_TIMEOUT_USE_DEFAULT) == FALSE) {
291 dbus_message_unref(message);
295 if (dbus_pending_call_set_notify(register_call, register_agent_cb,
296 NULL, NULL) == FALSE)
297 cleanup_register_call();
300 dbus_message_unref(message);
303 static void unregister_agent(void)
305 const char *path = AGENT_PATH;
306 const char *type = AGENT_TYPE;
307 DBusMessage *message;
309 if (agent_registered == FALSE)
310 return cleanup_register_call();
312 agent_registered = FALSE;
314 message = dbus_message_new_method_call(NEARD_SERVICE, NEARD_PATH,
315 NEARD_MANAGER_INTERFACE,
316 "UnregisterHandoverAgent");
317 if (message != NULL) {
318 dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH,
319 &path, DBUS_TYPE_STRING, &type, DBUS_TYPE_INVALID);
320 g_dbus_send_message(connection, message);
323 g_dbus_unregister_interface(connection,
324 AGENT_PATH, NEARD_AGENT_INTERFACE);
327 static void neard_is_present(DBusConnection *conn, void *user_data)
331 if (agent_registered == TRUE)
334 if (g_dbus_register_interface(connection, AGENT_PATH,
335 NEARD_AGENT_INTERFACE, neard_methods,
336 NULL, NULL, NULL, NULL) == TRUE)
340 static void neard_is_out(DBusConnection *conn, void *user_data)
344 if (agent_registered == TRUE) {
345 g_dbus_unregister_interface(connection,
346 AGENT_PATH, NEARD_AGENT_INTERFACE);
347 agent_registered = FALSE;
350 cleanup_register_call();
353 static int neard_init(void)
355 connection = connman_dbus_get_connection();
356 if (connection == NULL)
359 watch_id = g_dbus_add_service_watch(connection, NEARD_SERVICE,
360 neard_is_present, neard_is_out,
363 dbus_connection_unref(connection);
370 static void neard_exit(void)
375 g_dbus_remove_watch(connection, watch_id);
376 if (connection != NULL)
377 dbus_connection_unref(connection);
380 CONNMAN_PLUGIN_DEFINE(neard, "Neard handover plugin", VERSION,
381 CONNMAN_PLUGIN_PRIORITY_DEFAULT, neard_init, neard_exit)