a141c3bbae4719447757243ff553066d1359145d
[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 #include <linux/netlink.h>
34 #include <linux/rtnetlink.h>
35 #include <arpa/inet.h>
36 #include <netinet/in.h>
37
38 #include "caipnwmonitor.h"
39 #include "caadapterutils.h"
40 #include "logger.h"
41 #include "oic_malloc.h"
42 #include "oic_string.h"
43 #include <coap/utlist.h>
44
45 #define TAG "IP_MONITOR"
46
47 #define MAX_INTERFACE_INFO_LENGTH (1024)
48
49 #define NETLINK_MESSAGE_LENGTH  (4096)
50
51 /**
52  * Used to storing adapter changes callback interface.
53  */
54 static struct CAIPCBData_t *g_adapterCallbackList = NULL;
55
56 /**
57  * Create new interface item.
58  */
59 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
60                                          const char *addr, int flags);
61
62 /**
63  * Add new network interface in list.
64  */
65 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
66                                      char *name, int family, const char *addr, int flags);
67
68 /**
69  * Pass the changed network status through the stored callback.
70  */
71 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
72
73 /**
74  * Used to passing the network status changes to adapter.
75  */
76 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status);
77
78 /**
79  * Callback function to received connection state changes.
80  */
81 static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
82                                            void *userData);
83
84 /**
85  * Callback function to received device state changes.
86  */
87 static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData);
88
89
90 int CAGetPollingInterval(int interval)
91 {
92     return interval;
93 }
94
95 static void CAIPPassNetworkChangesToAdapter(CANetworkStatus_t status)
96 {
97     CAIPCBData_t *cbitem = NULL;
98     LL_FOREACH(g_adapterCallbackList, cbitem)
99     {
100         if (cbitem && cbitem->adapter)
101         {
102             cbitem->callback(cbitem->adapter, status);
103         }
104     }
105 }
106
107 CAResult_t CAIPSetNetworkMonitorCallback(CAIPAdapterStateChangeCallback callback,
108                                          CATransportAdapter_t adapter)
109 {
110     if (!callback)
111     {
112         OIC_LOG(ERROR, TAG, "callback is null");
113         return CA_STATUS_INVALID_PARAM;
114     }
115
116     CAIPCBData_t *cbitem = NULL;
117     LL_FOREACH(g_adapterCallbackList, cbitem)
118     {
119         if (cbitem && adapter == cbitem->adapter && callback == cbitem->callback)
120         {
121             OIC_LOG(DEBUG, TAG, "this callback is already added");
122             return CA_STATUS_OK;
123         }
124     }
125
126     cbitem = (CAIPCBData_t *)OICCalloc(1, sizeof(*cbitem));
127     if (!cbitem)
128     {
129         OIC_LOG(ERROR, TAG, "Malloc failed");
130         return CA_STATUS_FAILED;
131     }
132
133     cbitem->adapter = adapter;
134     cbitem->callback = callback;
135     LL_APPEND(g_adapterCallbackList, cbitem);
136
137     return CA_STATUS_OK;
138 }
139
140 CAResult_t CAIPUnSetNetworkMonitorCallback(CATransportAdapter_t adapter)
141 {
142     CAIPCBData_t *cbitem = NULL;
143     CAIPCBData_t *tmpCbitem = NULL;
144     LL_FOREACH_SAFE(g_adapterCallbackList, cbitem, tmpCbitem)
145     {
146         if (cbitem && adapter == cbitem->adapter)
147         {
148             OIC_LOG(DEBUG, TAG, "remove specific callback");
149             LL_DELETE(g_adapterCallbackList, cbitem);
150             OICFree(cbitem);
151             return CA_STATUS_OK;
152         }
153     }
154     return CA_STATUS_OK;
155 }
156
157 CAInterface_t *CAFindInterfaceChange()
158 {
159     CAInterface_t *foundNewInterface = NULL;
160     char buf[NETLINK_MESSAGE_LENGTH] = { 0 };
161     struct sockaddr_nl sa = { 0 };
162     struct iovec iov = { .iov_base = buf,
163                          .iov_len = sizeof (buf) };
164     struct msghdr msg = { .msg_name = (void *)&sa,
165                           .msg_namelen = sizeof (sa),
166                           .msg_iov = &iov,
167                           .msg_iovlen = 1 };
168
169     size_t len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
170
171     for (struct nlmsghdr *nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
172     {
173         if (nh != NULL && nh->nlmsg_type != RTM_NEWLINK)
174         {
175             continue;
176         }
177
178         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
179
180         int ifiIndex = ifi->ifi_index;
181         u_arraylist_t *iflist = CAIPGetInterfaceInformation(ifiIndex);
182
183         if ((!ifi || (ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING)))
184         {
185             continue;
186         }
187
188         if (!iflist)
189         {
190             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
191             return NULL;
192         }
193
194         uint32_t listLength = u_arraylist_length(iflist);
195         for (uint32_t i = 0; i < listLength; i++)
196         {
197             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
198             if (!ifitem)
199             {
200                 continue;
201             }
202
203             if ((int)ifitem->index != ifiIndex)
204             {
205                 continue;
206             }
207
208             foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
209                                                    ifitem->addr, ifitem->flags);
210             break;    // we found the one we were looking for
211         }
212         u_arraylist_destroy(iflist);
213     }
214     return foundNewInterface;
215 }
216
217 CAResult_t CAIPStartNetworkMonitor(CAIPAdapterStateChangeCallback callback,
218                                    CATransportAdapter_t adapter)
219 {
220     OIC_LOG(DEBUG, TAG, "IN");
221
222     if (!g_adapterCallbackList)
223     {
224         // Initialize Wifi service
225        wifi_error_e ret = wifi_initialize();
226        if (WIFI_ERROR_NONE != ret)
227        {
228            OIC_LOG(ERROR, TAG, "wifi_initialize failed");
229            return CA_STATUS_FAILED;
230        }
231
232        // Set callback for receiving state changes
233        ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
234        if (WIFI_ERROR_NONE != ret)
235        {
236            OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
237            return CA_STATUS_FAILED;
238        }
239
240        // Set callback for receiving connection state changes
241        ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
242        if (WIFI_ERROR_NONE != ret)
243        {
244            OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
245            return CA_STATUS_FAILED;
246        }
247     }
248
249     return CAIPSetNetworkMonitorCallback(callback, adapter);
250 }
251
252 CAResult_t CAIPStopNetworkMonitor(CATransportAdapter_t adapter)
253 {
254     OIC_LOG(DEBUG, TAG, "IN");
255
256     CAIPUnSetNetworkMonitorCallback(adapter);
257     if (!g_adapterCallbackList)
258     {
259         // Reset callback for receiving state changes
260        wifi_error_e ret = wifi_unset_device_state_changed_cb();
261        if (WIFI_ERROR_NONE != ret)
262        {
263            OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
264        }
265
266        // Reset callback for receiving connection state changes
267        ret = wifi_unset_connection_state_changed_cb();
268        if (WIFI_ERROR_NONE != ret)
269        {
270            OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
271        }
272
273        // Deinitialize Wifi service
274        ret = wifi_deinitialize();
275        if (WIFI_ERROR_NONE != ret)
276        {
277            OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
278        }
279     }
280
281     return CA_STATUS_OK;
282 }
283
284 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
285 {
286     u_arraylist_t *iflist = u_arraylist_create();
287     if (!iflist)
288     {
289         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
290         return NULL;
291     }
292
293     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
294     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
295
296     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
297     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
298     {
299         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
300         u_arraylist_destroy(iflist);
301         return NULL;
302     }
303
304     struct ifreq* ifr = ifc.ifc_req;
305     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
306     size_t ifreqsize = ifc.ifc_len;
307
308     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
309     {
310         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
311         if (!items)
312         {
313             OIC_LOG(ERROR, TAG, "OICRealloc failed");
314             goto exit;
315         }
316         caglobals.ip.nm.ifItems = items;
317         caglobals.ip.nm.sizeIfItems = ifreqsize;
318     }
319
320     caglobals.ip.nm.numIfItems = 0;
321     for (size_t i = 0; i < interfaces; i++)
322     {
323         struct ifreq* item = &ifr[i];
324         char *name = item->ifr_name;
325
326         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
327         {
328             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
329             continue;
330         }
331         int16_t flags = item->ifr_flags;
332         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
333         {
334             continue;
335         }
336         if (ioctl(s, SIOCGIFINDEX, item) < 0)
337         {
338             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
339             continue;
340         }
341
342         int ifindex = item->ifr_ifindex;
343         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
344         caglobals.ip.nm.numIfItems++;
345
346         if (desiredIndex && (ifindex != desiredIndex))
347         {
348             continue;
349         }
350
351         // Get address of network interface.
352         char addr[MAX_ADDR_STR_SIZE_CA] = { 0 };
353         struct sockaddr_in *sa = (struct sockaddr_in *)&item->ifr_addr;
354         inet_ntop(AF_INET, (void *)&(sa->sin_addr), addr, sizeof(addr));
355
356         // Add IPv4 interface
357         CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, addr, flags);
358         if (CA_STATUS_OK != result)
359         {
360             goto exit;
361         }
362
363         // Add IPv6 interface
364         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, addr, flags);
365         if (CA_STATUS_OK != result)
366         {
367             goto exit;
368         }
369     }
370     return iflist;
371
372 exit:
373     u_arraylist_destroy(iflist);
374     return NULL;
375 }
376
377 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
378                                      char *name, int family, const char *addr, int flags)
379 {
380     CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags);
381     if (!ifitem)
382     {
383         return CA_STATUS_FAILED;
384     }
385     bool result = u_arraylist_add(iflist, ifitem);
386     if (!result)
387     {
388         OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
389         OICFree(ifitem);
390         return CA_STATUS_FAILED;
391     }
392
393     return CA_STATUS_OK;
394 }
395
396 static CAInterface_t *CANewInterfaceItem(int index, char *name, int family,
397                                          const char *addr, int flags)
398 {
399     CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t));
400     if (!ifitem)
401     {
402         OIC_LOG(ERROR, TAG, "Malloc failed");
403         return NULL;
404     }
405
406     OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name);
407     ifitem->index = index;
408     ifitem->family = family;
409     OICStrcpy(ifitem->addr, sizeof(ifitem->addr), addr);
410     ifitem->flags = flags;
411
412     return ifitem;
413 }
414
415 void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap,
416                                     void *userData)
417 {
418     OIC_LOG(DEBUG, TAG, "IN");
419
420     if (WIFI_CONNECTION_STATE_ASSOCIATION == state
421         || WIFI_CONNECTION_STATE_CONFIGURATION == state)
422     {
423         OIC_LOG(DEBUG, TAG, "Connection is in Association State");
424         return;
425     }
426
427     if (WIFI_CONNECTION_STATE_CONNECTED == state)
428     {
429         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_UP);
430     }
431     else
432     {
433         CAIPPassNetworkChangesToAdapter(CA_INTERFACE_DOWN);
434     }
435
436     OIC_LOG(DEBUG, TAG, "OUT");
437 }
438
439 void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData)
440 {
441     OIC_LOG(DEBUG, TAG, "IN");
442
443     if (WIFI_DEVICE_STATE_ACTIVATED == state)
444     {
445         OIC_LOG(DEBUG, TAG, "Wifi is in Activated State");
446     }
447     else
448     {
449         CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL);
450         OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State");
451     }
452
453     OIC_LOG(DEBUG, TAG, "OUT");
454 }