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