88427f3b8ebbb579dd9ecd1c0a5d182b044c4742
[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 CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
43                                          uint32_t addr, int flags);
44
45 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
46                                      char *name, int family, uint32_t addr, int flags);
47
48 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
49                                            void *userData);
50
51 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
52
53
54 int CAGetPollingInterval(int interval)
55 {
56     return interval;
57 }
58
59 CAInterface_t *CAFindInterfaceChange()
60 {
61     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
62     struct ifconf ifc  = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
63
64     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
65     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
66     {
67         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
68         return NULL;
69     }
70
71     CAInterface_t *foundNewInterface = NULL;
72
73     struct ifreq* ifr = ifc.ifc_req;
74     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
75     size_t ifreqsize = ifc.ifc_len;
76
77     CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize);
78     if (!previous)
79     {
80         OIC_LOG(ERROR, TAG, "OICMalloc failed");
81         return NULL;
82     }
83
84     memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize);
85     size_t numprevious = caglobals.ip.nm.numIfItems;
86
87     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
88     {
89
90         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
91         if (!items)
92         {
93             OIC_LOG(ERROR, TAG, "OICRealloc failed");
94             OICFree(previous);
95             return NULL;
96         }
97         caglobals.ip.nm.ifItems = items;
98         caglobals.ip.nm.sizeIfItems = ifreqsize;
99     }
100
101     caglobals.ip.nm.numIfItems = 0;
102     for (size_t i = 0; i < interfaces; i++)
103     {
104         struct ifreq* item = &ifr[i];
105         char *name = item->ifr_name;
106         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
107         uint32_t ipv4addr = sa4->sin_addr.s_addr;
108
109         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
110         {
111             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
112             continue;
113         }
114         int16_t flags = item->ifr_flags;
115         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
116         {
117             continue;
118         }
119         if (ioctl(s, SIOCGIFINDEX, item) < 0)
120         {
121             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
122             continue;
123         }
124
125         int ifIndex = item->ifr_ifindex;
126         caglobals.ip.nm.ifItems[i].ifIndex = ifIndex;  // refill interface list
127         caglobals.ip.nm.numIfItems++;
128
129         if (foundNewInterface)
130         {
131             continue;   // continue updating interface list
132         }
133
134         // see if this interface didn't previously exist
135         bool found = false;
136         for (size_t j = 0; j < numprevious; j++)
137         {
138             if (ifIndex == previous[j].ifIndex)
139             {
140                 found = true;
141                 break;
142             }
143         }
144         if (found)
145         {
146             OIC_LOG_V(INFO, TAG, "Interface found: %s", name);
147             continue;
148         }
149
150         foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags);
151     }
152
153     OICFree(previous);
154     return foundNewInterface;
155 }
156
157 CAResult_t CAIPStartNetworkMonitor()
158 {
159     OIC_LOG(DEBUG, TAG, "IN");
160
161      // Initialize Wifi service
162     wifi_error_e ret = wifi_initialize();
163     if (WIFI_ERROR_NONE != ret)
164     {
165         OIC_LOG(ERROR, TAG, "wifi_initialize failed");
166         return CA_STATUS_FAILED;
167     }
168
169     // Set callback for receiving state changes
170     ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
171     if (WIFI_ERROR_NONE != ret)
172     {
173         OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
174         return CA_STATUS_FAILED;
175     }
176
177     // Set callback for receiving connection state changes
178     ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
179     if (WIFI_ERROR_NONE != ret)
180     {
181         OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
182         return CA_STATUS_FAILED;
183     }
184
185     OIC_LOG(DEBUG, TAG, "OUT");
186     return CA_STATUS_OK;
187 }
188
189 CAResult_t CAIPStopNetworkMonitor()
190 {
191     OIC_LOG(DEBUG, TAG, "IN");
192
193      // Reset callback for receiving state changes
194     wifi_error_e ret = wifi_unset_device_state_changed_cb();
195     if (WIFI_ERROR_NONE != ret)
196     {
197         OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
198     }
199
200     // Reset callback for receiving connection state changes
201     ret = wifi_unset_connection_state_changed_cb();
202     if (WIFI_ERROR_NONE != ret)
203     {
204         OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
205     }
206
207     // Deinitialize Wifi service
208     ret = wifi_deinitialize();
209     if (WIFI_ERROR_NONE != ret)
210     {
211         OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
212     }
213
214     OIC_LOG(DEBUG, TAG, "OUT");
215     return CA_STATUS_OK;
216 }
217
218 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
219 {
220     u_arraylist_t *iflist = u_arraylist_create();
221     if (!iflist)
222     {
223         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
224         return NULL;
225     }
226
227     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
228     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
229
230     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
231     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
232     {
233         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
234         u_arraylist_destroy(iflist);
235         return NULL;
236     }
237
238     struct ifreq* ifr = ifc.ifc_req;
239     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
240     size_t ifreqsize = ifc.ifc_len;
241
242     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
243     {
244         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
245         if (!items)
246         {
247             OIC_LOG(ERROR, TAG, "OICRealloc failed");
248             goto exit;
249         }
250         caglobals.ip.nm.ifItems = items;
251         caglobals.ip.nm.sizeIfItems = ifreqsize;
252     }
253
254     caglobals.ip.nm.numIfItems = 0;
255     for (size_t i = 0; i < interfaces; i++)
256     {
257         CAResult_t result = CA_STATUS_OK;
258         struct ifreq* item = &ifr[i];
259         char *name = item->ifr_name;
260         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
261         uint32_t ipv4addr = sa4->sin_addr.s_addr;
262
263         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
264         {
265             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
266             continue;
267         }
268         int16_t flags = item->ifr_flags;
269         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
270         {
271             continue;
272         }
273         if (ioctl(s, SIOCGIFINDEX, item) < 0)
274         {
275             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
276             continue;
277         }
278
279         int ifindex = item->ifr_ifindex;
280         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
281         caglobals.ip.nm.numIfItems++;
282
283         if (desiredIndex && (ifindex != desiredIndex))
284         {
285             continue;
286         }
287
288         // Add IPv4 interface
289         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
290         if (CA_STATUS_OK != result)
291         {
292             goto exit;
293         }
294
295         // Add IPv6 interface
296         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags);
297         if (CA_STATUS_OK != result)
298         {
299             goto exit;
300         }
301     }
302     return iflist;
303
304 exit:
305     u_arraylist_destroy(iflist);
306     return NULL;
307 }
308
309 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
310                                      char *name, int family, uint32_t addr, int flags)
311 {
312     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
313     if (!ifitem)
314     {
315         return CA_STATUS_FAILED;
316     }
317     bool result = u_arraylist_add(iflist, ifitem);
318     if (!result)
319     {
320         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
321         OICFree(ifitem);
322         return CA_STATUS_FAILED;
323     }
324
325     return CA_STATUS_OK;
326 }
327
328 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
329                                          uint32_t addr, int flags)
330 {
331     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
332     if (!ifitem)
333     {
334         OIC_LOG(ERROR, TAG, "Malloc failed");
335         return NULL;
336     }
337
338     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
339     ifitem->index = index;
340     ifitem->family = family;
341     ifitem->ipv4addr = addr;
342     ifitem->flags = flags;
343
344     return ifitem;
345 }
346
347 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
348                                     void *userData)
349 {
350     OIC_LOG(DEBUG, TAG, "IN");
351
352     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
353         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
354     {
355         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
356         return;
357     }
358
359     if (WIFI_CONNECTION_STATE_CONNECTED == state)
360     {
361         CAWakeUpForChange();
362     }
363     else
364     {
365         u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
366         if (!iflist)
367         {
368             OIC_LOG_V(ERROR, TAG, "get interface info failed");
369             return;
370         }
371         u_arraylist_destroy(iflist);
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 }