Using updated clatd's Dbus interface and Path values
[platform/core/connectivity/net-config.git] / src / wifi-tdls.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <time.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include "neterror.h"
27 #include "netdbus.h"
28 #include "netsupplicant.h"
29 #include "network-state.h"
30 #include <vconf.h>
31 #include <vconf-keys.h>
32 #include <arpa/inet.h>
33 #include <log.h>
34 #include "util.h"
35 #include "neterror.h"
36 #include "wifi-tdls.h"
37 #include <glib.h>
38
39 char *peer_mac = NULL;
40 int is_connected = 0;
41 static gint tdls_timer_id = 0;
42 int is_discover_broadcast = 0;
43 int is_timer_expired = 0;
44
45 #define TDLS_DISCOVER_TIMOUT 4 /*TDLS Unicast Discovery Timeout*/
46 #define TDLS_DISCOVER_BROADCAST_TIMOUT 8 /*TDLS Broadcast Discovery Timeout*/
47 static void stop_tdls_timer()
48 {
49         if (tdls_timer_id > 0) {
50                 g_source_remove(tdls_timer_id);
51                 tdls_timer_id = 0;
52         }
53 }
54
55 void __netconfig_wifi_notify_tdls_event(const char *sig_name, const char *peer_mac)
56 {
57         GVariantBuilder *builder;
58         GVariant *params;
59         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
60         g_variant_builder_add(builder, "{sv}", "peermac", g_variant_new_string(peer_mac));
61
62         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
63         g_variant_builder_unref(builder);
64
65         netconfig_dbus_emit_signal(NULL,
66                                 NETCONFIG_WIFI_PATH,
67                                 NETCONFIG_WIFI_INTERFACE,
68                                 sig_name,
69                                 params);
70
71         INFO("Sent signal (%s) Peer Mac (%s)", sig_name, peer_mac);
72 }
73
74 void __netconfig_wifi_notify_tdls_discover_event(const char *peer_mac, int discover_type)
75 {
76         GVariantBuilder *builder;
77         GVariant *params;
78         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
79
80         g_variant_builder_add(builder, "{sv}", "peermac", g_variant_new_string(peer_mac));
81         g_variant_builder_add(builder, "{sv}", "discover_type", g_variant_new_int32(discover_type));
82
83         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
84         g_variant_builder_unref(builder);
85
86         netconfig_dbus_emit_signal(NULL,
87                                 NETCONFIG_WIFI_PATH,
88                                 NETCONFIG_WIFI_INTERFACE,
89                                 "TDLSPeerFound",
90                                 params);
91
92         INFO("Sent signal (%s) Peer Mac (%s)", "TDLSPeerFound", peer_mac);
93 }
94
95 static gboolean _tdls_timer_discover_event(gpointer user_data)
96 {
97
98         if (tdls_timer_id == 0)
99                 return FALSE;
100
101         INFO("[TDLS Discover Timer Expired");
102         __netconfig_wifi_notify_tdls_discover_event("00:00:00:00:00:00", is_discover_broadcast);
103         is_discover_broadcast = 0;
104         stop_tdls_timer();
105         is_timer_expired = 1;
106
107         return FALSE;
108 }
109
110 static GVariant * __netconfig_wifi_tdls_send_dbus_str(const char* method, const char *str)
111 {
112         GVariant *message = NULL;
113         char *if_path = NULL;
114         GVariant *params = NULL;
115
116         if_path = netconfig_wifi_get_supplicant_interface();
117         if (if_path == NULL) {
118                 ERR("Fail to get wpa_supplicant DBus path");
119                 return NULL;
120         }
121
122         params = g_variant_new("(s)", str);
123         INFO("[TizenMW-->WPAS]Sent Dbus Method :[%s],value[%s]", method, str);
124         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE,
125                         if_path, SUPPLICANT_INTERFACE ".Interface", method, params);
126
127         g_free(if_path);
128         INFO("TDLS Returned from Blocking method for Send DBUS Command");
129         return message;
130 }
131
132 static unsigned char _netconfig_freq_to_channel(int freq)
133 {
134         if (freq < 2412 || freq > 5825 ||
135                 (freq > 2484 && freq < 5180)) {
136                 ERR("Invalid Frequence Range");
137                 return 0;
138         }
139         if (freq >= 5180)
140                 return 36 + (freq - 5180)/5;
141         else if (freq <= 2472)
142                 return 1 + (freq - 2412)/5;
143         else if (freq == 2484)
144                 return 14;
145         else
146                 return 0;
147 }
148
149 static unsigned char _netconfig_get_operating_class(int freq)
150 {
151         unsigned char channel = 0;
152         unsigned char oper_class = 0;
153
154         channel = _netconfig_freq_to_channel(freq);
155
156         if (channel) {
157                 /* Operating class 81 - 2.4 GHz band channels 1..13 */
158                 if (channel >= 1 && channel <= 13)
159                         oper_class = 81;
160                 /* Operating class 115 - 5 GHz, channels 36-48 */
161                 else if (channel >= 36 && channel <= 48)
162                         oper_class = 115;
163                 /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
164                 else
165                         oper_class = 124;
166
167                 INFO("TDLS: Operating Class  is [%d]", oper_class);
168                 return oper_class;
169         }
170         return 0;
171 }
172
173 gboolean handle_tdls_connect(Wifi *wifi, GDBusMethodInvocation *context,
174                         gchar *peer_mac_Addr)
175 {
176         DBG("[TizenMW-->WPAS]: TDLS Setup Request: [%s]", peer_mac_Addr);
177
178         if (is_connected) {
179                 ERR(" Already TDLS Connection !!!");
180         } else {
181                 GVariant *message = NULL;
182                 message = __netconfig_wifi_tdls_send_dbus_str("TDLSSetup", (const char*)peer_mac_Addr);
183
184                 if (message == NULL) {
185                         ERR(" TDLS : failed to connect !!!");
186                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsConnect");
187                         return TRUE;
188                 }
189
190                 DBG("[TizenMW<--WPAS] TDLS DBUS Command sent successfully");
191                 g_variant_unref(message);
192                 is_connected = 1;
193         }
194
195         wifi_complete_tdls_connect(wifi, context, 1);
196         return TRUE;
197 }
198
199 gboolean handle_tdls_discover(Wifi *wifi, GDBusMethodInvocation *context,
200                         gchar *peer_mac_Addr)
201 {
202         DBG("TDLS Discover Request: [%s]", peer_mac_Addr);
203         int discover_timeout = 0;
204
205         GVariant *message = NULL;
206
207         if (tdls_timer_id > 0) {
208                 DBG(" TDLS Discover is already progress !!!");
209                 wifi_complete_tdls_discover(wifi, context, NETCONFIG_ERROR_TDLS_ALREADY_DONE);
210                 return TRUE;
211         }
212
213         message = __netconfig_wifi_tdls_send_dbus_str("TDLSDiscover", (const char*)peer_mac_Addr);
214
215         if (message == NULL) {
216                 ERR(" TDLS : failed to discover !!!");
217                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsDiscover");
218                 wifi_complete_tdls_discover(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_DISCOVER);
219                 return TRUE;
220         }
221
222         DBG(" TDLS DBUS Command sent successfully");
223         g_variant_unref(message);
224
225         if (NULL != strstr(peer_mac_Addr, "ff:ff:ff:ff:ff:ff")) {
226                 DBG("TDLS: Broadcast Discovery");
227                 is_discover_broadcast = 1;
228                 discover_timeout = TDLS_DISCOVER_BROADCAST_TIMOUT;
229         } else {
230                 is_discover_broadcast = 0;
231                 discover_timeout = TDLS_DISCOVER_TIMOUT;
232         }
233
234         is_timer_expired = 0;
235         tdls_timer_id = g_timeout_add_seconds(discover_timeout,
236                                         _tdls_timer_discover_event, NULL);
237
238         wifi_complete_tdls_discover(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
239         return TRUE;
240 }
241
242 gboolean handle_tdls_disconnect(Wifi *wifi, GDBusMethodInvocation *context,
243                         gchar *peer_mac_Addr)
244 {
245         DBG("[TizenMW-->WPAS]: TDLS Teardown Request: [%s]", peer_mac_Addr);
246
247         if (!is_connected) {
248                 ERR(" Already TDLS disconnection !!!");
249                 wifi_complete_tdls_disconnect(wifi, context, NETCONFIG_ERROR_TDLS_ALREADY_DONE);
250         } else {
251                 GVariant *message = NULL;
252                 message = __netconfig_wifi_tdls_send_dbus_str("TDLSTeardown", (const char*)peer_mac_Addr);
253
254                 if (message == NULL) {
255                         ERR(" TDLS : failed to disconnect !!!");
256                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsDisconnect");
257                         return TRUE;
258                 }
259
260                 DBG("[TizenMW<--WPAS] TDLS DBUS Command sent successfully");
261                 g_variant_unref(message);
262                 is_connected = 0;
263         }
264
265         wifi_complete_tdls_disconnect(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
266         return TRUE;
267 }
268
269 gboolean handle_tdls_connected_peer(Wifi *wifi, GDBusMethodInvocation *context)
270 {
271         DBG("[TizenMW-->WPAS]: TDLS Connected Peer Request: ");
272
273         GVariant *message = NULL;
274         const gchar* reply_str = NULL;
275
276         if (peer_mac == NULL) {
277                 INFO("TDLS: No Active Connection");
278                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
279                 return TRUE;
280         }
281         message = __netconfig_wifi_tdls_send_dbus_str("TDLSStatus", (const char*)peer_mac);
282         if (message == NULL) {
283                 ERR(" TDLS : No active TDLS Link Setup !!!");
284                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
285                 return TRUE;
286         }
287
288         g_variant_get(message, "(&s)", &reply_str);
289         INFO("TDLS reply: [%s]", reply_str);
290         INFO("TDLS :peer_mac [%s]", peer_mac);
291
292         if (g_strcmp0("connected", reply_str) != 0) {
293                 ERR("[TizenMW<--WPAS] TDLS Connection not available");
294                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
295                 g_variant_unref(message);
296                 return TRUE;
297         }
298
299         INFO("TDLS Connection available, Peer Mac address %s", peer_mac);
300         wifi_complete_tdls_connected_peer(wifi, context, peer_mac);
301
302         g_variant_unref(message);
303         return TRUE;
304 }
305
306 gboolean handle_tdls_channel_switch(Wifi *wifi, GDBusMethodInvocation *context,
307                         gchar *peer_mac_Addr, int freq)
308 {
309         GVariant *message = NULL;
310         GVariantBuilder *builder;
311         GVariant *params;
312         char *if_path = NULL;
313         unsigned char oper_class = 0;
314
315         if (peer_mac_Addr == NULL) {
316                 ERR("TDLS: Invalid Parameter");
317                 wifi_complete_tdls_channel_switch(wifi, context,
318                                                         NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
319                 return TRUE;
320         }
321
322         oper_class = _netconfig_get_operating_class(freq);
323
324         if (!oper_class) {
325                 ERR("TDLS: Invalid Parameter");
326                 wifi_complete_tdls_channel_switch(wifi, context,
327                                                         NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
328                 return TRUE;
329         }
330
331         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
332
333         g_variant_builder_add(builder, "{sv}", "PeerAddress", g_variant_new_string(peer_mac_Addr));
334         g_variant_builder_add(builder, "{sv}", "Frequency", g_variant_new_uint32(freq));
335         g_variant_builder_add(builder, "{sv}", "OperClass", g_variant_new_byte(oper_class));
336         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
337         g_variant_builder_unref(builder);
338
339         if_path = netconfig_wifi_get_supplicant_interface();
340
341         if (if_path == NULL) {
342                 ERR("Fail to get wpa_supplicant DBus path");
343                 wifi_complete_tdls_channel_switch(wifi, context,
344                                                 NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
345                 return TRUE;
346         }
347
348         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE,
349                                 if_path, SUPPLICANT_INTERFACE ".Interface", "TDLSChannelSwitch", params);
350
351         g_free(if_path);
352         if (message == NULL) {
353                 ERR(" TDLS : Fail to Process TDLS Channel Switch Request !!!");
354                 wifi_complete_tdls_channel_switch(wifi, context,
355                                                 NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
356                 return TRUE;
357         }
358
359         INFO("TDLS Channel Change Request: Success");
360         wifi_complete_tdls_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
361
362         g_variant_unref(message);
363         return TRUE;
364 }
365
366
367 gboolean handle_tdls_cancel_channel_switch(Wifi *wifi, GDBusMethodInvocation *context,
368                         gchar *peer_mac_Addr)
369 {
370         GVariant *message = NULL;
371
372         if (peer_mac_Addr == NULL) {
373                 INFO("TDLS: Invalid Parameter");
374                 wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
375                 return TRUE;
376         }
377         message = __netconfig_wifi_tdls_send_dbus_str("TDLSCancelChannelSwitch", (const char*)peer_mac_Addr);
378         if (message == NULL) {
379                 ERR(" TDLS : Fail to TDLS Cancel Channel Swicth Request !!!");
380                 wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
381                 return TRUE;
382         }
383
384         INFO("TDLS Cancel Channel Swicth Request : Success");
385         wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
386
387         g_variant_unref(message);
388         return TRUE;
389 }
390
391 void netconfig_wifi_tdls_connected_event(GVariant *message)
392 {
393
394         DBG("WiFi TDLS Connected EVENT");
395         if (is_connected == 1) {
396                 INFO("TDLS Peer already connected");
397                 g_free(peer_mac);
398         }
399
400         g_variant_get(message, "(s)", &peer_mac);
401         INFO("Peer Mac Address: [%s]", peer_mac);
402
403         is_connected = 1;
404         __netconfig_wifi_notify_tdls_event("TDLSConnect", peer_mac);
405 }
406
407 void netconfig_wifi_tdls_disconnected_event(GVariant *message)
408 {
409         DBG("WiFi TDLS Disconnected EVENT");
410         const gchar *peer_mac_addr = NULL;
411
412         g_variant_get(message, "(&s)", &peer_mac_addr);
413         if (g_strcmp0(peer_mac, peer_mac_addr) == 0) {
414                 INFO("TDLS Peer Disconnected Mac Address: [%s]", peer_mac);
415                 is_connected = 0;
416                 __netconfig_wifi_notify_tdls_event("TDLSDisconnect", peer_mac);
417         } else
418                 INFO("TDLS Peer Disconnected peer_mac(%s) != peer_mac_address(%s)", peer_mac, peer_mac_addr);
419 }
420
421
422 void netconfig_wifi_tdls_peer_found_event(GVariant *message)
423 {
424         DBG("WiFi TDLS Discovery EVENT Received !!");
425         const gchar *peer_mac_addr = NULL;
426
427         if (!is_timer_expired) {
428
429                 g_variant_get(message, "(s)", &peer_mac_addr);
430                 INFO("Discover Peer Mac Address: [%s]", peer_mac_addr);
431
432                 if (is_discover_broadcast == 0)
433                         stop_tdls_timer();
434
435                 __netconfig_wifi_notify_tdls_discover_event(peer_mac_addr, is_discover_broadcast);
436         } else
437                 DBG("Timer expired: Do not process the TDLS Discovery Event");
438 }
439