Remove the TIZEN_FEATURE_IP_OVER_EAPOL build flag
[platform/core/connectivity/wifi-direct-manager.git] / src / wifi-direct-group.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012 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 /**
21  * This file implements wifi direct group functions.
22  *
23  * @file                wifi-direct-group.c
24  * @author      Gibyoung Kim (lastkgb.kim@samsung.com)
25  * @version     0.7
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31
32 #include <glib.h>
33
34 #include <wifi-direct.h>
35
36 #include "wifi-direct-ipc.h"
37 #include "wifi-direct-manager.h"
38 #include "wifi-direct-state.h"
39 #include "wifi-direct-peer.h"
40 #include "wifi-direct-oem.h"
41 #include "wifi-direct-group.h"
42 #include "wifi-direct-util.h"
43 #include "wifi-direct-session.h"
44 #include "wifi-direct-log.h"
45
46 /* Check the group instance which has same interface name,
47  * before using this function */
48 wfd_group_s *wfd_create_group(void *data, wfd_oem_event_s *group_info)
49 {
50         __WDS_LOG_FUNC_ENTER__;
51         wfd_group_s *group = NULL;
52         wfd_manager_s *manager = (wfd_manager_s*) data;
53         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
54
55         if (!manager || !group_info) {
56                 WDS_LOGE("Invalid parameter");
57                 __WDS_LOG_FUNC_EXIT__;
58                 return NULL;
59         }
60         wfd_oem_group_data_s *edata = (wfd_oem_group_data_s *)group_info->edata;
61
62         if (!edata) {
63                 WDS_LOGE("Invalid parameter");
64                 __WDS_LOG_FUNC_EXIT__;
65                 return NULL;
66         }
67
68         group = manager->group;
69         if (group) {
70                 WDS_LOGE("Group already exist");
71                 __WDS_LOG_FUNC_EXIT__;
72                 return NULL;
73         }
74
75         errno = 0;
76         group = (wfd_group_s*) g_try_malloc0(sizeof(wfd_group_s));
77         if (!group) {
78                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
79                 WDS_LOGE("Failed to allocate memory for group. [%s]", error_buf);
80                 __WDS_LOG_FUNC_EXIT__;
81                 return NULL;
82         }
83
84         memcpy(group->ifname, group_info->ifname, IFACE_NAME_LEN);
85         group->ifname[IFACE_NAME_LEN] = '\0';
86         group->role = group_info->dev_role;
87         memcpy(group->go_dev_addr, edata->go_dev_addr, MACADDR_LEN);
88
89         g_strlcpy(group->ssid, edata->ssid, DEV_NAME_LEN + 1);
90         g_strlcpy(group->passphrase, edata->pass, PASSPHRASE_LEN_MAX + 1);
91         memset(manager->local->passphrase, 0x0, PASSPHRASE_LEN_MAX + 1);
92         group->freq = edata->freq;
93
94         manager->group = group;
95         manager->local->dev_role = group_info->dev_role;
96
97         wfd_util_dhcps_start(group->ifname);
98         group->pending = FALSE;
99         WDS_LOGD("Role is Group Owner. DHCP Server started");
100
101         __WDS_LOG_FUNC_EXIT__;
102         return group;
103 }
104
105 /* Used for CTRL-EVENT_CONNECTED event that comes before group created */
106 wfd_group_s *wfd_create_pending_group(void *data, unsigned char * bssid)
107 {
108         __WDS_LOG_FUNC_ENTER__;
109         wfd_group_s *group = NULL;
110         wfd_manager_s *manager = (wfd_manager_s*) data;
111         char error_buf[MAX_SIZE_ERROR_BUFFER] = {0, };
112
113         if (!manager || !bssid) {
114                 WDS_LOGE("Invalid parameter");
115                 __WDS_LOG_FUNC_EXIT__;
116                 return NULL;
117         }
118
119         group = manager->group;
120         if (group) {
121                 WDS_LOGE("Group already exist");
122                 __WDS_LOG_FUNC_EXIT__;
123                 return NULL;
124         }
125
126         errno = 0;
127         group = (wfd_group_s*) g_try_malloc0(sizeof(wfd_group_s));
128         if (!group) {
129                 strerror_r(errno, error_buf, MAX_SIZE_ERROR_BUFFER);
130                 WDS_LOGE("Failed to allocate memory for group. [%s]", error_buf);
131                 __WDS_LOG_FUNC_EXIT__;
132                 return NULL;
133         }
134
135         memcpy(group->bssid, bssid, MACADDR_LEN);
136         group->flags &= WFD_GROUP_FLAG_NONE;
137         group->pending = TRUE;
138
139         __WDS_LOG_FUNC_EXIT__;
140         return group;
141 }
142
143 int wfd_group_complete(void *data, wfd_oem_event_s *group_info)
144 {
145         __WDS_LOG_FUNC_ENTER__;
146         wfd_manager_s *manager = (wfd_manager_s*) data;
147         wfd_session_s *session = NULL;
148         wfd_group_s *group = NULL;
149         wfd_device_s *peer = NULL;
150
151         if (!manager || !group_info) {
152                 WDS_LOGE("Invalid parameter");
153                 __WDS_LOG_FUNC_EXIT__;
154                 return -1;
155         }
156         wfd_oem_group_data_s *edata = (wfd_oem_group_data_s *)group_info->edata;
157
158         if (!edata) {
159                 WDS_LOGE("Invalid parameter");
160                 __WDS_LOG_FUNC_EXIT__;
161                 return -1;
162         }
163
164         group = manager->group;
165         if (!group) {
166                 WDS_LOGE("Group not found");
167                 __WDS_LOG_FUNC_EXIT__;
168                 return -1;
169         }
170
171         g_strlcpy(group->ifname, group_info->ifname, IFACE_NAME_LEN + 1);
172         group->role = group_info->dev_role;
173         memcpy(group->go_dev_addr, edata->go_dev_addr, MACADDR_LEN);
174
175         g_strlcpy(group->ssid, edata->ssid, DEV_NAME_LEN + 1);
176         g_strlcpy(group->passphrase, edata->pass, PASSPHRASE_LEN_MAX + 1);
177         memset(manager->local->passphrase, 0x0, PASSPHRASE_LEN_MAX + 1);
178         group->freq = edata->freq;
179         if (edata->is_persistent)
180                 group->flags |= WFD_GROUP_FLAG_PERSISTENT;
181
182         manager->local->dev_role = group_info->dev_role;
183         group->pending = FALSE;
184
185         session = manager->session;
186         peer = wfd_session_get_peer(session);
187         if (!peer && !(group->flags & WFD_GROUP_FLAG_AUTONOMOUS)) {
188                 if (!session && (group->flags & WFD_GROUP_FLAG_PERSISTENT)) {
189                         WDS_LOGE("Group created by supplicant is persistent group.");
190                         /**
191                          * 1. When GO, start dhcpd and start session at peer joined event.
192                          * 2. When GC, start dhcpc after adding GO Address as peer.
193                          */
194                         if (group->role == WFD_DEV_ROLE_GC) {
195                                 peer = wfd_peer_find_by_addr(manager,
196                                                              group->go_dev_addr);
197                                 if (!peer) {
198                                         WDS_LOGI("Add peer GO");
199                                         peer = wfd_add_peer(manager,
200                                                             group->go_dev_addr,
201                                                             "PEER-GO");
202                                 }
203                         }
204                 } else {
205                         WDS_LOGD("Failed to find peer by device address[" MACSECSTR "]",
206                                                         MAC2SECSTR(edata->go_dev_addr));
207                         __WDS_LOG_FUNC_EXIT__;
208                         return -1;
209                 }
210         }
211
212         if (group->role == WFD_DEV_ROLE_GO) {
213                 wfd_util_dhcps_start(group->ifname);
214                 WDS_LOGD("Role is Group Owner. DHCP Server started");
215         } else {
216                 if (!peer) {
217                         WDS_LOGE("Peer is not in the session");
218                         __WDS_LOG_FUNC_EXIT__;
219                         return -1;
220                 }
221
222                 WDS_LOGD("Role is Group Client.complete session and add peer to member");
223                 memcpy(peer->intf_addr, group->go_dev_addr, MACADDR_LEN);
224                 wfd_group_add_member(group, peer->dev_addr);
225                 session->state = SESSION_STATE_COMPLETED;
226                 peer->state = WFD_PEER_STATE_CONNECTED;
227                 if (edata->ip_addr[3] && edata->ip_addr_go[3]) {
228                         peer->ip_type = WFD_IP_TYPE_OVER_EAPOL;
229                         memcpy(peer->client_ip_addr, edata->ip_addr, IPADDR_LEN);
230                         WDS_LOGE("Peer's client IP [" IPSTR "]", IP2STR((char*) &peer->client_ip_addr));
231                         memcpy(peer->go_ip_addr, edata->ip_addr_go, IPADDR_LEN);
232                         WDS_LOGE("Peer's GO IP [" IPSTR "]", IP2STR((char*) &peer->go_ip_addr));
233                 }
234                 if (peer->ip_type != WFD_IP_TYPE_OVER_EAPOL)
235                         wfd_util_dhcpc_start(group->ifname, peer);
236         }
237
238         __WDS_LOG_FUNC_EXIT__;
239         return 0;
240 }
241
242 int wfd_destroy_group(void *data)
243 {
244         __WDS_LOG_FUNC_ENTER__;
245         wfd_group_s *group = NULL;
246         wfd_manager_s *manager = (wfd_manager_s*) data;
247         GList *temp = NULL;
248         wfd_device_s *member = NULL;
249         int count = 0;
250
251         if (!data) {
252                 WDS_LOGE("Invalid parameter");
253                 __WDS_LOG_FUNC_EXIT__;
254                 return -1;
255         }
256
257         group = manager->group;
258         if (!group) {
259                 WDS_LOGE("Group not exist");
260                 __WDS_LOG_FUNC_EXIT__;
261                 return -1;
262         }
263         manager->group = NULL;
264
265         if (group->pending == FALSE) {
266                 wfd_util_ip_unset(group->ifname);
267                 if (group->role == WFD_DEV_ROLE_GO)
268                         wfd_util_dhcps_stop(group->ifname);
269                 else
270                         wfd_util_dhcpc_stop(group->ifname);
271         }
272         memset(manager->local->ip_addr, 0x0, IPADDR_LEN);
273
274         temp = g_list_first(group->members);
275         while (temp && count < group->member_count) {
276                 member = temp->data;
277                 WDS_LOGD("%dth member[%s] will be removed", count, member->dev_name);
278                 g_free(member);
279                 member = NULL;
280                 temp = g_list_next(temp);
281                 count++;
282         }
283
284         if (group->members) {
285                 g_list_free(group->members);
286                 group->members = NULL;
287         }
288
289         g_free(group);
290
291         manager->local->dev_role = WFD_DEV_ROLE_NONE;
292         __WDS_LOG_FUNC_EXIT__;
293         return 0;
294 }
295
296 #if 0
297 int wfd_group_get_channel(wfd_group_s *group)
298 {
299         __WDS_LOG_FUNC_ENTER__;
300
301         if (!group) {
302                 WDS_LOGE("Invalid parameter");
303                 __WDS_LOG_FUNC_EXIT__;
304                 return -1;
305         }
306
307         __WDS_LOG_FUNC_EXIT__;
308         return group->freq;
309 }
310 #endif
311
312 int wfd_group_is_autonomous(wfd_group_s *group)
313 {
314         __WDS_LOG_FUNC_ENTER__;
315
316         if (!group) {
317                 WDS_LOGE("Invalid parameter");
318                 __WDS_LOG_FUNC_EXIT__;
319                 return -1;
320         }
321
322         __WDS_LOG_FUNC_EXIT__;
323         return ((group->flags & WFD_GROUP_FLAG_AUTONOMOUS) == WFD_GROUP_FLAG_AUTONOMOUS);
324 }
325
326 #if 0
327 int wfd_group_get_members()
328 {
329         __WDS_LOG_FUNC_ENTER__;
330
331         __WDS_LOG_FUNC_EXIT__;
332         return 0;
333 }
334
335 int wfd_group_make_persistent()
336 {
337         __WDS_LOG_FUNC_ENTER__;
338
339         __WDS_LOG_FUNC_EXIT__;
340         return 0;
341 }
342
343 int wfd_group_get_flags(wfd_group_s *group)
344 {
345         __WDS_LOG_FUNC_ENTER__;
346
347         if (!group) {
348                 WDS_LOGE("Invalid parameter");
349                 __WDS_LOG_FUNC_EXIT__;
350                 return -1;
351         }
352
353         __WDS_LOG_FUNC_EXIT__;
354         return group->flags;
355 }
356 #endif
357
358 wfd_device_s *wfd_group_find_member_by_addr(wfd_group_s *group, unsigned char *addr)
359 {
360         __WDS_LOG_FUNC_ENTER__;
361         GList *temp = NULL;
362         wfd_device_s *member = NULL;
363
364         if (!group || !addr) {
365                 WDS_LOGE("Invalid parameter");
366                 __WDS_LOG_FUNC_EXIT__;
367                 return NULL;
368         }
369
370         if (!group->member_count) {
371                 WDS_LOGE("There is no members");
372                 __WDS_LOG_FUNC_EXIT__;
373                 return NULL;
374         }
375
376         temp = g_list_first(group->members);
377         while (temp) {
378                 member = temp->data;
379                 if (!memcmp(member->intf_addr, addr, MACADDR_LEN) ||
380                                 !memcmp(member->dev_addr, addr, MACADDR_LEN)) {
381                         WDS_LOGD("Member found");
382                         break;
383                 }
384                 temp = g_list_next(temp);
385                 member = NULL;
386         }
387
388         __WDS_LOG_FUNC_EXIT__;
389         return member;
390 }
391
392 int wfd_group_add_member(wfd_group_s *group, unsigned char *addr)
393 {
394         __WDS_LOG_FUNC_ENTER__;
395         wfd_device_s *member = NULL;
396         wfd_manager_s *manager = wfd_get_manager();
397
398         if (!group || !addr) {
399                 WDS_LOGE("Invalid parameter");
400                 __WDS_LOG_FUNC_EXIT__;
401                 return -1;
402         }
403
404         member = wfd_group_find_member_by_addr(group, addr);
405         if (member) {
406                 WDS_LOGE("Member already exist");
407                 __WDS_LOG_FUNC_EXIT__;
408                 return -1;
409         }
410
411         member = wfd_peer_find_by_addr(manager, addr);
412         if (!member)
413                 WDS_LOGE("Peer not found");
414
415         group->members = g_list_prepend(group->members, member);
416         group->member_count++;
417
418         manager->peers = g_list_remove(manager->peers, member);
419         manager->peer_count--;
420
421         __WDS_LOG_FUNC_EXIT__;
422         return 0;
423 }
424
425 int wfd_group_remove_member(wfd_group_s *group, unsigned char *addr)
426 {
427         __WDS_LOG_FUNC_ENTER__;
428         wfd_device_s *member = NULL;
429         wfd_manager_s *manager = wfd_get_manager();
430
431         if (!group || !addr) {
432                 WDS_LOGE("Invalid parameter");
433                 __WDS_LOG_FUNC_EXIT__;
434                 return -1;
435         }
436
437         if (group->member_count == 0) {
438                 WDS_LOGE("There is no members");
439                 __WDS_LOG_FUNC_EXIT__;
440                 return -1;
441         }
442
443         member = wfd_group_find_member_by_addr(group, addr);
444         if (!member) {
445                 WDS_LOGD("Member not found [MAC: " MACSECSTR "]",
446                                                 MAC2SECSTR(addr));
447                 __WDS_LOG_FUNC_EXIT__;
448                 return -1;
449         }
450
451         group->members = g_list_remove(group->members, member);
452         g_free(member);
453         group->member_count--;
454
455         if (group->role == WFD_DEV_ROLE_GO) {
456                 if (!group->member_count && wfd_util_is_remove_group_allowed()) {
457                         wfd_oem_destroy_group(manager->oem_ops, group->ifname);
458                         wfd_destroy_group(manager);
459                         wfd_peer_clear_all(manager);
460                 }
461         } else {
462                 wfd_oem_destroy_group(manager->oem_ops, group->ifname);
463                 wfd_destroy_group(manager);
464                 wfd_peer_clear_all(manager);
465         }
466
467         __WDS_LOG_FUNC_EXIT__;
468         return 0;
469 }