6e331fc1d8497a8f8c8f3ebff01ab069aea457bc
[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
44 #define TDLS_DISCOVER_TIMOUT 4 /*TDLS Unicast Discovery Timeout*/
45 #define TDLS_DISCOVER_BROADCAST_TIMOUT 8 /*TDLS Broadcast Discovery Timeout*/
46 static void stop_tdls_timer()
47 {
48         if (tdls_timer_id > 0) {
49                 g_source_remove(tdls_timer_id);
50                 tdls_timer_id = 0;
51         }
52 }
53
54 void __netconfig_wifi_notify_tdls_event(const char *sig_name, const char *peer_mac)
55 {
56         GVariantBuilder *builder;
57         GVariant *params;
58         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
59         g_variant_builder_add(builder, "{sv}", "peermac", g_variant_new_string(peer_mac));
60
61         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
62         g_variant_builder_unref(builder);
63
64         netconfig_dbus_emit_signal(NULL,
65                                 NETCONFIG_WIFI_PATH,
66                                 NETCONFIG_WIFI_INTERFACE,
67                                 sig_name,
68                                 params);
69
70         INFO("Sent signal (%s) Peer Mac (%s)", sig_name, peer_mac);
71 }
72
73 void __netconfig_wifi_notify_tdls_discover_event(const char *peer_mac, int discover_type)
74 {
75         GVariantBuilder *builder;
76         GVariant *params;
77         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
78
79         g_variant_builder_add(builder, "{sv}", "peermac", g_variant_new_string(peer_mac));
80         g_variant_builder_add(builder, "{sv}", "discover_type", g_variant_new_int32(discover_type));
81
82         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
83         g_variant_builder_unref(builder);
84
85         netconfig_dbus_emit_signal(NULL,
86                                 NETCONFIG_WIFI_PATH,
87                                 NETCONFIG_WIFI_INTERFACE,
88                                 "TDLSPeerFound",
89                                 params);
90
91         INFO("Sent signal (%s) Peer Mac (%s)", "TDLSPeerFound", peer_mac);
92 }
93
94 static gboolean _tdls_timer_discover_event(gpointer user_data)
95 {
96
97         if (tdls_timer_id == 0)
98                 return FALSE;
99
100         INFO("[TDLS Discover Timer Expired");
101         __netconfig_wifi_notify_tdls_discover_event("00:00:00:00:00:00", is_discover_broadcast);
102         is_discover_broadcast = 0;
103         stop_tdls_timer();
104         return FALSE;
105 }
106
107 static GVariant * __netconfig_wifi_tdls_send_dbus_str(const char* method, const char *str)
108 {
109         GVariant *message = NULL;
110         const char *if_path = NULL;
111         GVariant *params = NULL;
112
113         if_path = netconfig_wifi_get_supplicant_interface();
114         if (if_path == NULL) {
115                 ERR("Fail to get wpa_supplicant DBus path");
116                 return NULL;
117         }
118
119         params = g_variant_new("(s)", str);
120         INFO("[TizenMW-->WPAS]Sent Dbus Method :[%s],value[%s]", method, str);
121         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE,
122                         if_path, SUPPLICANT_INTERFACE ".Interface", method, params);
123
124         INFO("TDLS Returned from Blocking method for Send DBUS Command");
125         return message;
126 }
127
128 static unsigned char _netconfig_freq_to_channel(int freq)
129 {
130         if (freq < 2412 || freq > 5825 ||
131                 (freq > 2484 && freq < 5180)) {
132                 ERR("Invalid Frequence Range");
133                 return 0;
134         }
135         if (freq >= 5180)
136                 return 36 + (freq - 5180)/5;
137         else if (freq <= 2472)
138                 return 1 + (freq - 2412)/5;
139         else if (freq == 2484)
140                 return 14;
141         else
142                 return 0;
143 }
144
145 static unsigned char _netconfig_get_operating_class(int freq)
146 {
147         unsigned char channel = 0;
148         unsigned char oper_class = 0;
149
150         channel = _netconfig_freq_to_channel(freq);
151
152         if (channel) {
153                 /* Operating class 81 - 2.4 GHz band channels 1..13 */
154                 if (channel >= 1 && channel <= 13)
155                         oper_class = 81;
156                 /* Operating class 115 - 5 GHz, channels 36-48 */
157                 else if (channel >= 36 && channel <= 48)
158                         oper_class = 115;
159                 /* Operating class 124 - 5 GHz, channels 149,153,157,161 */
160                 else
161                         oper_class = 124;
162
163                 INFO("TDLS: Operating Class  is [%d]", oper_class);
164                 return oper_class;
165         }
166         return 0;
167 }
168
169 gboolean handle_tdls_connect(Wifi *wifi, GDBusMethodInvocation *context,
170                         gchar *peer_mac_Addr)
171 {
172         DBG("[TizenMW-->WPAS]: TDLS Setup Request: [%s]", peer_mac_Addr);
173
174         if (is_connected) {
175                 ERR(" Already TDLS Connection !!!");
176         } else {
177                 GVariant *message = NULL;
178                 message = __netconfig_wifi_tdls_send_dbus_str("TDLSSetup", (const char*)peer_mac_Addr);
179
180                 if (message == NULL) {
181                         ERR(" TDLS : failed to connect !!!");
182                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsConnect");
183                         return FALSE;
184                 }
185
186                 DBG("[TizenMW<--WPAS] TDLS DBUS Command sent successfully");
187                 g_variant_unref(message);
188                 is_connected = 1;
189         }
190
191         wifi_complete_tdls_connect(wifi, context, 1);
192         return TRUE;
193 }
194
195 gboolean handle_tdls_discover(Wifi *wifi, GDBusMethodInvocation *context,
196                         gchar *peer_mac_Addr)
197 {
198         DBG("TDLS Discover Request: [%s]", peer_mac_Addr);
199         int discover_timeout = 0;
200
201         GVariant *message = NULL;
202         message = __netconfig_wifi_tdls_send_dbus_str("TDLSDiscover", (const char*)peer_mac_Addr);
203
204         if (message == NULL) {
205                 ERR(" TDLS : failed to discover !!!");
206                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsDiscover");
207                 wifi_complete_tdls_discover(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_DISCOVER);
208                 return FALSE;
209         }
210
211         DBG(" TDLS DBUS Command sent successfully");
212         g_variant_unref(message);
213
214         if (NULL != strstr(peer_mac_Addr, "ff:ff:ff:ff:ff:ff")) {
215                 DBG("TDLS: Broadcast Discovery");
216                 is_discover_broadcast = 1;
217                 discover_timeout = TDLS_DISCOVER_BROADCAST_TIMOUT;
218         } else {
219                 is_discover_broadcast = 0;
220                 discover_timeout = TDLS_DISCOVER_TIMOUT;
221         }
222
223         tdls_timer_id = g_timeout_add_seconds(discover_timeout,
224                                         _tdls_timer_discover_event, NULL);
225
226         wifi_complete_tdls_discover(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
227         return TRUE;
228 }
229
230 gboolean handle_tdls_disconnect(Wifi *wifi, GDBusMethodInvocation *context,
231                         gchar *peer_mac_Addr)
232 {
233         DBG("[TizenMW-->WPAS]: TDLS Teardown Request: [%s]", peer_mac_Addr);
234
235         if (!is_connected) {
236                 ERR(" Already TDLS disconnection !!!");
237                 wifi_complete_tdls_disconnect(wifi, context, NETCONFIG_ERROR_TDLS_ALREADY_DONE);
238         } else {
239                 GVariant *message = NULL;
240                 message = __netconfig_wifi_tdls_send_dbus_str("TDLSTeardown", (const char*)peer_mac_Addr);
241
242                 if (message == NULL) {
243                         ERR(" TDLS : failed to disconnect !!!");
244                         netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailTdlsDisconnect");
245                         return FALSE;
246                 }
247
248                 DBG("[TizenMW<--WPAS] TDLS DBUS Command sent successfully");
249                 g_variant_unref(message);
250                 is_connected = 0;
251         }
252
253         wifi_complete_tdls_disconnect(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
254         return TRUE;
255 }
256
257 gboolean handle_tdls_connected_peer(Wifi *wifi, GDBusMethodInvocation *context)
258 {
259         DBG("[TizenMW-->WPAS]: TDLS Connected Peer Request: ");
260
261         GVariant *message = NULL;
262         const gchar* reply_str = NULL;
263
264         if (peer_mac == NULL) {
265                 INFO("TDLS: No Active Connection");
266                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
267                 return TRUE;
268         }
269         message = __netconfig_wifi_tdls_send_dbus_str("TDLSStatus", (const char*)peer_mac);
270         if (message == NULL) {
271                 ERR(" TDLS : No active TDLS Link Setup !!!");
272                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
273                 return TRUE;
274         }
275
276         g_variant_get(message, "(&s)", &reply_str);
277         INFO("TDLS reply: [%s]", reply_str);
278         INFO("TDLS :peer_mac [%s]", peer_mac);
279
280         if (g_strcmp0("connected", reply_str) != 0) {
281                 ERR("[TizenMW<--WPAS] TDLS Connection not available");
282                 wifi_complete_tdls_connected_peer(wifi, context, "00.00.00.00.00.00");
283                 g_variant_unref(message);
284                 return TRUE;
285         }
286
287         INFO("TDLS Connection available, Peer Mac address %s", peer_mac);
288         wifi_complete_tdls_connected_peer(wifi, context, peer_mac);
289
290         g_variant_unref(message);
291         return TRUE;
292 }
293
294 gboolean handle_tdls_channel_switch(Wifi *wifi, GDBusMethodInvocation *context,
295                         gchar *peer_mac_Addr, int freq)
296 {
297         GVariant *message = NULL;
298         GVariantBuilder *builder;
299         GVariant *params;
300         const char *if_path = NULL;
301         unsigned char oper_class = 0;
302
303         if (peer_mac_Addr == NULL) {
304                 ERR("TDLS: Invalid Parameter");
305                 wifi_complete_tdls_channel_switch(wifi, context,
306                                                         NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
307                 return TRUE;
308         }
309
310         oper_class = _netconfig_get_operating_class(freq);
311
312         if (!oper_class) {
313                 ERR("TDLS: Invalid Parameter");
314                 wifi_complete_tdls_channel_switch(wifi, context,
315                                                         NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
316                 return TRUE;
317         }
318
319         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
320
321         g_variant_builder_add(builder, "{sv}", "PeerAddress", g_variant_new_string(peer_mac_Addr));
322         g_variant_builder_add(builder, "{sv}", "Frequency", g_variant_new_int32(freq));
323         g_variant_builder_add(builder, "{sv}", "OperClass", g_variant_new_byte(oper_class));
324         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
325         g_variant_builder_unref(builder);
326
327         if_path = netconfig_wifi_get_supplicant_interface();
328
329         if (if_path == NULL) {
330                 ERR("Fail to get wpa_supplicant DBus path");
331                 wifi_complete_tdls_channel_switch(wifi, context,
332                                                 NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
333                 return TRUE;
334         }
335
336         message = netconfig_invoke_dbus_method(SUPPLICANT_SERVICE,
337                                 if_path, SUPPLICANT_INTERFACE ".Interface", "TDLSChannelSwitch", params);
338
339         if (message == NULL) {
340                 ERR(" TDLS : Fail to Process TDLS Channel Switch Request !!!");
341                 wifi_complete_tdls_channel_switch(wifi, context,
342                                                 NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
343                 return TRUE;
344         }
345
346         INFO("TDLS Channel Change Request: Success");
347         wifi_complete_tdls_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
348
349         g_variant_unref(message);
350         return TRUE;
351 }
352
353
354 gboolean handle_tdls_cancel_channel_switch(Wifi *wifi, GDBusMethodInvocation *context,
355                         gchar *peer_mac_Addr)
356 {
357         GVariant *message = NULL;
358
359         if (peer_mac_Addr == NULL) {
360                 INFO("TDLS: Invalid Parameter");
361                 wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
362                 return TRUE;
363         }
364         message = __netconfig_wifi_tdls_send_dbus_str("TDLSCancelChannelSwitch", (const char*)peer_mac_Addr);
365         if (message == NULL) {
366                 ERR(" TDLS : Fail to TDLS Cancel Channel Swicth Request !!!");
367                 wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_FAIL_CHANNEL_SWITCH);
368                 return TRUE;
369         }
370
371         INFO("TDLS Cancel Channel Swicth Request : Success");
372         wifi_complete_tdls_cancel_channel_switch(wifi, context, NETCONFIG_ERROR_TDLS_NO_ERROR);
373
374         g_variant_unref(message);
375         return TRUE;
376 }
377
378 void netconfig_wifi_tdls_connected_event(GVariant *message)
379 {
380
381         DBG("WiFi TDLS Connected EVENT");
382         if (is_connected == 1) {
383                 INFO("TDLS Peer already connected");
384                 g_free(peer_mac);
385         }
386
387         g_variant_get(message, "(s)", &peer_mac);
388         INFO("Peer Mac Address: [%s]", peer_mac);
389
390         is_connected = 1;
391         __netconfig_wifi_notify_tdls_event("TDLSConnect", peer_mac);
392 }
393
394 void netconfig_wifi_tdls_disconnected_event(GVariant *message)
395 {
396         DBG("WiFi TDLS Disconnected EVENT");
397         const gchar *peer_mac_addr = NULL;
398
399         g_variant_get(message, "(&s)", &peer_mac_addr);
400         if (g_strcmp0(peer_mac, peer_mac_addr) == 0) {
401                 INFO("TDLS Peer Disconnected Mac Address: [%s]", peer_mac);
402                 is_connected = 0;
403                 __netconfig_wifi_notify_tdls_event("TDLSDisconnect", peer_mac);
404         } else
405                 INFO("TDLS Peer Disconnected peer_mac(%s) != peer_mac_address(%s)", peer_mac, peer_mac_addr);
406 }
407
408
409 void netconfig_wifi_tdls_peer_found_event(GVariant *message)
410 {
411         DBG("WiFi TDLS Discovery EVENT");
412         const gchar *peer_mac_addr = NULL;
413
414         g_variant_get(message, "(s)", &peer_mac_addr);
415         INFO("Discover Peer Mac Address: [%s]", peer_mac_addr);
416
417
418         if (is_discover_broadcast == 0)
419                 stop_tdls_timer();
420
421         __netconfig_wifi_notify_tdls_discover_event(peer_mac_addr, is_discover_broadcast);
422 }
423