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