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