Merge branch 'master' into windows-port
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / tizen / caipnwmonitor.c
1 /******************************************************************
2 *
3 * Copyright 2014 Samsung Electronics All Rights Reserved.
4 *
5 *
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 *      http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 ******************************************************************/
20
21 #include "caipinterface.h"
22
23 #include <sys/types.h>
24 #include <ifaddrs.h>
25 #include <net/if.h>
26 #include <sys/socket.h>
27 #include <netdb.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <sys/ioctl.h>
32 #include <wifi.h>
33
34 #include "caadapterutils.h"
35 #include "logger.h"
36 #include "oic_malloc.h"
37 #include "oic_string.h"
38
39 #define TAG "IP_MONITOR"
40 #define MAX_INTERFACE_INFO_LENGTH (1024)
41
42 static CAIPConnectionStateChangeCallback g_networkChangeCallback;
43
44 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
45                                          uint32_t addr, int flags);
46
47 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
48                                      char *name, int family, uint32_t addr, int flags);
49
50 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
51                                            void *userData);
52
53 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
54
55
56 int CAGetPollingInterval(int interval)
57 {
58     return interval;
59 }
60
61 void CAIPSetNetworkMonitorCallback(CAIPConnectionStateChangeCallback callback)
62 {
63     g_networkChangeCallback = callback;
64 }
65
66 CAInterface_t *CAFindInterfaceChange()
67 {
68     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
69     struct ifconf ifc  = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
70
71     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
72     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
73     {
74         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
75         return NULL;
76     }
77
78     CAInterface_t *foundNewInterface = NULL;
79
80     struct ifreq* ifr = ifc.ifc_req;
81     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
82     size_t ifreqsize = ifc.ifc_len;
83
84     CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
85     if (!previous)
86     {
87         OIC_LOG(ERROR, TAG, "OICMalloc failed");
88         return NULL;
89     }
90
91     memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
92     size_t numprevious = caglobals.ip.nm.numIfItems;
93
94     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
95     {
96
97         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
98         if (!items)
99         {
100             OIC_LOG(ERROR, TAG, "OICRealloc failed");
101             OICFree(previous);
102             return NULL;
103         }
104         caglobals.ip.nm.ifItems = items;
105         caglobals.ip.nm.sizeIfItems = ifreqsize;
106     }
107
108     caglobals.ip.nm.numIfItems = 0;
109     for (size_t i = 0; i < interfaces; i++)
110     {
111         struct ifreq* item = &ifr[i];
112         char *name = item->ifr_name;
113         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
114         uint32_t ipv4addr = sa4->sin_addr.s_addr;
115
116         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
117         {
118             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
119             continue;
120         }
121         int16_t flags = item->ifr_flags;
122         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
123         {
124             continue;
125         }
126         if (ioctl(s, SIOCGIFINDEX, item) < 0)
127         {
128             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
129             continue;
130         }
131
132         int ifIndex = item->ifr_ifindex;
133         caglobals.ip.nm.ifItems[i].ifIndex = ifIndex;  // refill interface list
134         caglobals.ip.nm.numIfItems++;
135
136         if (foundNewInterface)
137         {
138             continue;   // continue updating interface list
139         }
140
141         // see if this interface didn't previously exist
142         bool found = false;
143         for (size_t j = 0; j < numprevious; j++)
144         {
145             if (ifIndex == previous[j].ifIndex)
146             {
147                 found = true;
148                 break;
149             }
150         }
151         if (found)
152         {
153             OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
154             continue;
155         }
156
157         foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
158     }
159
160     OICFree(previous);
161     return foundNewInterface;
162 }
163
164 CAResult_t CAIPStartNetworkMonitor()
165 {
166     OIC_LOG(DEBUG, TAG, "IN");
167
168      // Initialize Wifi service
169     wifi_error_e ret = wifi_initialize();
170     if (WIFI_ERROR_NONE != ret)
171     {
172         OIC_LOG(ERROR, TAG, "wifi_initialize failed");
173         return CA_STATUS_FAILED;
174     }
175
176     // Set callback for receiving state changes
177     ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
178     if (WIFI_ERROR_NONE != ret)
179     {
180         OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
181         return CA_STATUS_FAILED;
182     }
183
184     // Set callback for receiving connection state changes
185     ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
186     if (WIFI_ERROR_NONE != ret)
187     {
188         OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
189         return CA_STATUS_FAILED;
190     }
191
192     OIC_LOG(DEBUG, TAG, "OUT");
193     return CA_STATUS_OK;
194 }
195
196 CAResult_t CAIPStopNetworkMonitor()
197 {
198     OIC_LOG(DEBUG, TAG, "IN");
199
200      // Reset callback for receiving state changes
201     wifi_error_e ret = wifi_unset_device_state_changed_cb();
202     if (WIFI_ERROR_NONE != ret)
203     {
204         OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
205     }
206
207     // Reset callback for receiving connection state changes
208     ret = wifi_unset_connection_state_changed_cb();
209     if (WIFI_ERROR_NONE != ret)
210     {
211         OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
212     }
213
214     // Deinitialize Wifi service
215     ret = wifi_deinitialize();
216     if (WIFI_ERROR_NONE != ret)
217     {
218         OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
219     }
220
221     OIC_LOG(DEBUG, TAG, "OUT");
222     return CA_STATUS_OK;
223 }
224
225 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
226 {
227     u_arraylist_t *iflist = u_arraylist_create();
228     if (!iflist)
229     {
230         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
231         return NULL;
232     }
233
234     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
235     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
236
237     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
238     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
239     {
240         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
241         u_arraylist_destroy(iflist);
242         return NULL;
243     }
244
245     struct ifreq* ifr = ifc.ifc_req;
246     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
247     size_t ifreqsize = ifc.ifc_len;
248
249     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
250     {
251         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
252         if (!items)
253         {
254             OIC_LOG(ERROR, TAG, "OICRealloc failed");
255             goto exit;
256         }
257         caglobals.ip.nm.ifItems = items;
258         caglobals.ip.nm.sizeIfItems = ifreqsize;
259     }
260
261     caglobals.ip.nm.numIfItems = 0;
262     for (size_t i = 0; i < interfaces; i++)
263     {
264         struct ifreq* item = &ifr[i];
265         char *name = item->ifr_name;
266         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
267         uint32_t ipv4addr = sa4->sin_addr.s_addr;
268
269         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
270         {
271             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
272             continue;
273         }
274         int16_t flags = item->ifr_flags;
275         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
276         {
277             continue;
278         }
279         if (ioctl(s, SIOCGIFINDEX, item) < 0)
280         {
281             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
282             continue;
283         }
284
285         int ifindex = item->ifr_ifindex;
286         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
287         caglobals.ip.nm.numIfItems++;
288
289         if (desiredIndex && (ifindex != desiredIndex))
290         {
291             continue;
292         }
293
294         // Add IPv4 interface
295         CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
296         if (CA_STATUS_OK != result)
297         {
298             goto exit;
299         }
300
301         // Add IPv6 interface
302         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
303         if (CA_STATUS_OK != result)
304         {
305             goto exit;
306         }
307     }
308     return iflist;
309
310 exit:
311     u_arraylist_destroy(iflist);
312     return NULL;
313 }
314
315 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
316                                      char *name, int family, uint32_t addr, int flags)
317 {
318     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
319     if (!ifitem)
320     {
321         return CA_STATUS_FAILED;
322     }
323     bool result = u_arraylist_add(iflist, ifitem);
324     if (!result)
325     {
326         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
327         OICFree(ifitem);
328         return CA_STATUS_FAILED;
329     }
330
331     return CA_STATUS_OK;
332 }
333
334 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
335                                          uint32_t addr, int flags)
336 {
337     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
338     if (!ifitem)
339     {
340         OIC_LOG(ERROR, TAG, "Malloc failed");
341         return NULL;
342     }
343
344     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
345     ifitem->index = index;
346     ifitem->family = family;
347     ifitem->ipv4addr = addr;
348     ifitem->flags = flags;
349
350     return ifitem;
351 }
352
353 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
354                                     void *userData)
355 {
356     OIC_LOG(DEBUG, TAG, "IN");
357
358     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
359         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
360     {
361         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
362         return;
363     }
364
365     if (WIFI_CONNECTION_STATE_CONNECTED == state)
366     {
367         g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_UP);
368     }
369     else
370     {
371         g_networkChangeCallback(CA_ADAPTER_IP, CA_INTERFACE_DOWN);
372     }
373
374     OIC_LOG(DEBUG, TAG, "OUT");
375 }
376
377 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
378 {
379     OIC_LOG(DEBUG, TAG, "IN");
380
381     if (WIFI_DEVICE_STATE_ACTIVATED == state)
382     {
383         OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
384     }
385     else
386     {
387         CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
388         OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
389     }
390
391     OIC_LOG(DEBUG, TAG, "OUT");
392 }