Imported Upstream version 1.1.1
[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                                          uint32_t addr, int flags);
53
54 static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index,
55                                      char *name, int family, uint32_t 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
125             foundNewInterface = CANewInterfaceItem(ifitem->index, ifitem->name, ifitem->family,
126                                                    ifitem->ipv4addr, ifitem->flags);
127             break;    // we found the one we were looking for
128         }
129         u_arraylist_destroy(iflist);
130     }
131     return foundNewInterface;
132 }
133
134 CAResult_t CAIPStartNetworkMonitor()
135 {
136     OIC_LOG(DEBUG, TAG, "IN");
137
138      // Initialize Wifi service
139     wifi_error_e ret = wifi_initialize();
140     if (WIFI_ERROR_NONE != ret)
141     {
142         OIC_LOG(ERROR, TAG, "wifi_initialize failed");
143         return CA_STATUS_FAILED;
144     }
145
146     // Set callback for receiving state changes
147     ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL);
148     if (WIFI_ERROR_NONE != ret)
149     {
150         OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed");
151         return CA_STATUS_FAILED;
152     }
153
154     // Set callback for receiving connection state changes
155     ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL);
156     if (WIFI_ERROR_NONE != ret)
157     {
158         OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed");
159         return CA_STATUS_FAILED;
160     }
161
162     OIC_LOG(DEBUG, TAG, "OUT");
163     return CA_STATUS_OK;
164 }
165
166 CAResult_t CAIPStopNetworkMonitor()
167 {
168     OIC_LOG(DEBUG, TAG, "IN");
169
170      // Reset callback for receiving state changes
171     wifi_error_e ret = wifi_unset_device_state_changed_cb();
172     if (WIFI_ERROR_NONE != ret)
173     {
174         OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed");
175     }
176
177     // Reset callback for receiving connection state changes
178     ret = wifi_unset_connection_state_changed_cb();
179     if (WIFI_ERROR_NONE != ret)
180     {
181         OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed");
182     }
183
184     // Deinitialize Wifi service
185     ret = wifi_deinitialize();
186     if (WIFI_ERROR_NONE != ret)
187     {
188         OIC_LOG(ERROR, TAG, "wifi_deinitialize failed");
189     }
190
191     OIC_LOG(DEBUG, TAG, "OUT");
192     return CA_STATUS_OK;
193 }
194
195 u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex)
196 {
197     u_arraylist_t *iflist = u_arraylist_create();
198     if (!iflist)
199     {
200         OIC_LOG_V(ERROR, TAG, "Failed to create iflist: %s", strerror(errno));
201         return NULL;
202     }
203
204     char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 };
205     struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf };
206
207     int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd;
208     if (ioctl(s, SIOCGIFCONF, &ifc) < 0)
209     {
210         OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno));
211         u_arraylist_destroy(iflist);
212         return NULL;
213     }
214
215     struct ifreq* ifr = ifc.ifc_req;
216     size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]);
217     size_t ifreqsize = ifc.ifc_len;
218
219     if (ifreqsize > caglobals.ip.nm.sizeIfItems)
220     {
221         CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize);
222         if (!items)
223         {
224             OIC_LOG(ERROR, TAG, "OICRealloc failed");
225             goto exit;
226         }
227         caglobals.ip.nm.ifItems = items;
228         caglobals.ip.nm.sizeIfItems = ifreqsize;
229     }
230
231     caglobals.ip.nm.numIfItems = 0;
232     for (size_t i = 0; i < interfaces; i++)
233     {
234         struct ifreq* item = &ifr[i];
235         char *name = item->ifr_name;
236         struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr;
237         uint32_t ipv4addr = sa4->sin_addr.s_addr;
238
239         if (ioctl(s, SIOCGIFFLAGS, item) < 0)
240         {
241             OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno));
242             continue;
243         }
244         int16_t flags = item->ifr_flags;
245         if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING))
246         {
247             continue;
248         }
249         if (ioctl(s, SIOCGIFINDEX, item) < 0)
250         {
251             OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno));
252             continue;
253         }
254
255         int ifindex = item->ifr_ifindex;
256         caglobals.ip.nm.ifItems[i].ifIndex = ifindex;
257         caglobals.ip.nm.numIfItems++;
258
259         if (desiredIndex && (ifindex != desiredIndex))
260         {
261             continue;
262         }
263
264         // Add IPv4 interface
265         CAResult_t result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags);
266         if (CA_STATUS_OK != result)
267         {
268             goto exit;
269         }
270
271         // Add IPv6 interface
272         result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, 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, uint32_t 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                                          uint32_t 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     ifitem->ipv4addr = 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 }