New IP Adapter supports IPv6
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / caipserver.c
1 /*****************************************************************j
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 #ifndef __APPLE__
24 #include <asm/types.h>
25 #else
26     #ifndef IPV6_ADD_MEMBERSHIP
27         #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
28     #endif
29 #endif
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <fcntl.h>
36 #include <sys/select.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <net/if.h>
40 #include <errno.h>
41 #ifdef __linux__
42 #include <linux/netlink.h>
43 #include <linux/rtnetlink.h>
44 #endif
45
46 #include "pdu.h"
47 #include "caadapterutils.h"
48 #ifdef __WITH_DTLS__
49 #include "caadapternetdtls.h"
50 #endif
51 #include "camutex.h"
52 #include "oic_malloc.h"
53 #include "oic_string.h"
54
55 /**
56  * @def TAG
57  * @brief Logging tag for module name
58  */
59 #define TAG "IP_SERVER"
60
61 #define SELECT_TIMEOUT 1     // select() seconds (and termination latency)
62
63 #define IPv4_MULTICAST     "224.0.1.187"
64 static struct in_addr IPv4MulticastAddress = { 0 };
65
66 #define IPv6_DOMAINS       16
67 #define IPv6_MULTICAST_INT "ff01::fd"
68 static struct in6_addr IPv6MulticastAddressInt;
69 #define IPv6_MULTICAST_LNK "ff02::fd"
70 static struct in6_addr IPv6MulticastAddressLnk;
71 #define IPv6_MULTICAST_RLM "ff03::fd"
72 static struct in6_addr IPv6MulticastAddressRlm;
73 #define IPv6_MULTICAST_ADM "ff04::fd"
74 static struct in6_addr IPv6MulticastAddressAdm;
75 #define IPv6_MULTICAST_SIT "ff05::fd"
76 static struct in6_addr IPv6MulticastAddressSit;
77 #define IPv6_MULTICAST_ORG "ff08::fd"
78 static struct in6_addr IPv6MulticastAddressOrg;
79 #define IPv6_MULTICAST_GLB "ff0e::fd"
80 static struct in6_addr IPv6MulticastAddressGlb;
81
82 static char *ipv6mcnames[IPv6_DOMAINS] = {
83     NULL,
84     IPv6_MULTICAST_INT,
85     IPv6_MULTICAST_LNK,
86     IPv6_MULTICAST_RLM,
87     IPv6_MULTICAST_ADM,
88     IPv6_MULTICAST_SIT,
89     NULL,
90     NULL,
91     IPv6_MULTICAST_ORG,
92     NULL,
93     NULL,
94     NULL,
95     NULL,
96     NULL,
97     IPv6_MULTICAST_GLB,
98     NULL
99 };
100
101 static CAIPExceptionCallback g_exceptionCallback;
102
103 static CAIPPacketReceivedCallback g_packetReceivedCallback;
104
105 static void CAHandleNetlink();
106 static void CAApplyInterfaces();
107 static void CAFindReadyMessage();
108 static void CASelectReturned(fd_set *readFds, int ret);
109 static CAResult_t CAReceiveMessage(int fd, CATransportFlags_t flags);
110
111 #define SET(TYPE, FDS) \
112     if (caglobals.ip.TYPE.fd != -1) \
113     { \
114         FD_SET(caglobals.ip.TYPE.fd, FDS); \
115     }
116
117 #define ISSET(TYPE, FDS, FLAGS) \
118     if (caglobals.ip.TYPE.fd != -1 && FD_ISSET(caglobals.ip.TYPE.fd, FDS)) \
119     { \
120         fd = caglobals.ip.TYPE.fd; \
121         flags = FLAGS; \
122     }
123
124 static void CAReceiveHandler(void *data)
125 {
126     OIC_LOG(DEBUG, TAG, "IN");
127
128     while (!caglobals.ip.terminate)
129     {
130         CAFindReadyMessage();
131     }
132
133     OIC_LOG(DEBUG, TAG, "OUT");
134 }
135
136 static void CAFindReadyMessage()
137 {
138     fd_set readFds;
139     struct timeval timeout;
140
141     timeout.tv_sec = caglobals.ip.selectTimeout;
142     timeout.tv_usec = 0;
143     struct timeval *tv = caglobals.ip.selectTimeout == -1 ? NULL : &timeout;
144
145     FD_ZERO(&readFds);
146     SET(u6,  &readFds)
147     SET(u6s, &readFds)
148     SET(u4,  &readFds)
149     SET(u4s, &readFds)
150     SET(m6,  &readFds)
151     SET(m6s, &readFds)
152     SET(m4,  &readFds)
153     SET(m4s, &readFds)
154     if (caglobals.ip.shutdownFds[0] != -1)
155     {
156         FD_SET(caglobals.ip.shutdownFds[0], &readFds);
157     }
158     if (caglobals.ip.netlinkFd != -1)
159     {
160         FD_SET(caglobals.ip.netlinkFd, &readFds);
161     }
162
163     int ret = select(caglobals.ip.maxfd + 1, &readFds, NULL, NULL, tv);
164
165     if (caglobals.ip.terminate)
166     {
167         OIC_LOG_V(DEBUG, TAG, "Packet receiver Stop request received.");
168         return;
169     }
170     if (ret <= 0)
171     {
172         if (ret < 0)
173         {
174             OIC_LOG_V(FATAL, TAG, "select error %s", strerror(errno));
175         }
176         return;
177     }
178
179     CASelectReturned(&readFds, ret);
180 }
181
182 static void CASelectReturned(fd_set *readFds, int ret)
183 {
184     int fd = -1;
185     CATransportFlags_t flags = CA_DEFAULT_FLAGS;
186
187     while (!caglobals.ip.terminate)
188     {
189         ISSET(u6,  readFds, CA_IPV6)
190         else ISSET(u6s, readFds, CA_IPV6 | CA_SECURE)
191         else ISSET(u4,  readFds, CA_IPV4)
192         else ISSET(u4s, readFds, CA_IPV4 | CA_SECURE)
193         else ISSET(m6,  readFds, CA_MULTICAST | CA_IPV6)
194         else ISSET(m6s, readFds, CA_MULTICAST | CA_IPV6 | CA_SECURE)
195         else ISSET(m4,  readFds, CA_MULTICAST | CA_IPV4)
196         else ISSET(m4s, readFds, CA_MULTICAST | CA_IPV4 | CA_SECURE)
197         else if (FD_ISSET(caglobals.ip.netlinkFd, readFds))
198         {
199             CAHandleNetlink();
200             break;
201         }
202         else
203         {
204             break;
205         }
206
207         (void)CAReceiveMessage(fd, flags);
208         FD_CLR(fd, readFds);
209     }
210 }
211
212 static CAResult_t CAReceiveMessage(int fd, CATransportFlags_t flags)
213 {
214     char recvBuffer[COAP_MAX_PDU_SIZE];
215
216     struct sockaddr_storage srcAddr;
217     socklen_t srcAddrLen = sizeof (srcAddr);
218
219     ssize_t recvLen = recvfrom(fd,
220                                recvBuffer,
221                                sizeof (recvBuffer),
222                                0,
223                                (struct sockaddr *)&srcAddr,
224                                &srcAddrLen);
225     if (-1 == recvLen)
226     {
227         OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
228         return CA_STATUS_FAILED;
229     }
230
231     CAEndpoint_t ep = { CA_ADAPTER_IP, flags };
232
233     if (flags & CA_IPV6)
234     {
235         ep.interface = ((struct sockaddr_in6 *)&srcAddr)->sin6_scope_id;
236         ((struct sockaddr_in6 *)&srcAddr)->sin6_scope_id = 0;
237     }
238     CAConvertAddrToName(&srcAddr, ep.addr, &ep.port);
239
240     if (flags & CA_SECURE)
241     {
242 #ifdef __WITH_DTLS__
243         int ret = CAAdapterNetDtlsDecrypt(&ep, (uint8_t *)recvBuffer, recvLen);
244         OIC_LOG_V(DEBUG, TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret);
245 #else
246         OIC_LOG(ERROR, TAG, "Encrypted message but no DTLS");
247 #endif
248     }
249     else
250     {
251         if (g_packetReceivedCallback)
252         {
253             g_packetReceivedCallback(&ep, recvBuffer, recvLen);
254         }
255     }
256
257     return CA_STATUS_OK;
258 }
259
260 void CAIPPullData()
261 {
262     OIC_LOG(DEBUG, TAG, "IN");
263     OIC_LOG(DEBUG, TAG, "OUT");
264 }
265
266 static int CACreateSocket(int family, uint16_t *port)
267 {
268     int socktype = SOCK_DGRAM;
269     #ifdef SOCK_CLOEXEC
270     socktype |= SOCK_CLOEXEC;
271     #endif
272     int fd = socket(family, socktype, IPPROTO_UDP);
273     if (-1 == fd)
274     {
275         OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
276         return -1;
277     }
278
279     #ifndef SOCK_CLOEXEC
280     int fl = fcntl(fd, F_GETFD);
281     if (-1 == fl || -1 == fcntl(fd, F_SETFD, fl|FD_CLOEXEC))
282     {
283         OIC_LOG_V(ERROR, TAG, "set FD_CLOEXEC failed: %s", strerror(errno));
284         close(fd);
285         return -1;
286     }
287     #endif
288
289     struct sockaddr_storage sa = { family };
290     if (family == AF_INET6)
291     {
292         int on = 1;
293         if (-1 == setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
294         {
295             OIC_LOG_V(ERROR, TAG, "IPV6_V6ONLY failed: %s", strerror(errno));
296         }
297         ((struct sockaddr_in6 *)&sa)->sin6_port = htons(*port);
298     }
299     else
300     {
301         ((struct sockaddr_in *)&sa)->sin_port = htons(*port);
302     }
303
304     if (*port)  // use the given port
305     {
306         int on = 1;
307         if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)))
308         {
309             OIC_LOG_V(ERROR, TAG, "SO_REUSEADDR failed: %s", strerror(errno));
310             close(fd);
311             return -1;
312         }
313     }
314
315     if (-1 == bind(fd, (struct sockaddr *)&sa, sizeof(sa)))
316     {
317         OIC_LOG_V(ERROR, TAG, "bind socket failed: %s", strerror(errno));
318         close(fd);
319         return -1;
320     }
321
322     if (!*port)  // return the assigned port
323     {
324         struct sockaddr_storage sa;
325         socklen_t socklen = sizeof (sa);
326         if (-1 == getsockname(fd, (struct sockaddr *)&sa, &socklen))
327         {
328             OIC_LOG_V(ERROR, TAG, "getsockname failed: %s", strerror(errno));
329             close(fd);
330             return -1;
331         }
332         *port = ntohs(family == AF_INET6 ?
333                       ((struct sockaddr_in6 *)&sa)->sin6_port :
334                       ((struct sockaddr_in *)&sa)->sin_port);
335     }
336
337     return fd;
338 }
339
340 #define CHECKFD(FD) \
341     if (FD > caglobals.ip.maxfd) \
342         caglobals.ip.maxfd = FD;
343 #define NEWSOCKET(FAMILY, NAME) \
344     caglobals.ip.NAME.fd = CACreateSocket(FAMILY, &caglobals.ip.NAME.port); \
345     CHECKFD(caglobals.ip.NAME.fd)
346
347 static void CAInitializeNetlink()
348 {
349 #ifdef __linux__
350     // create NETLINK fd for interface change notifications
351     struct sockaddr_nl sa = { AF_NETLINK, 0, 0, RTMGRP_LINK };
352
353     caglobals.ip.netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
354     if (caglobals.ip.netlinkFd == -1)
355     {
356         OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
357     }
358     else
359     {
360         int r = bind(caglobals.ip.netlinkFd, (struct sockaddr *)&sa, sizeof (sa));
361         if (r)
362         {
363             OIC_LOG_V(ERROR, TAG, "netlink bind failed: %s", strerror(errno));
364             close(caglobals.ip.netlinkFd);
365             caglobals.ip.netlinkFd = -1;
366         }
367         else
368         {
369             CHECKFD(caglobals.ip.netlinkFd);
370         }
371     }
372 #endif
373 }
374
375 static void CAInitializePipe()
376 {
377     caglobals.ip.selectTimeout = -1;
378 #ifdef HAVE_PIPE2
379     int ret = pipe2(caglobals.ip.shutdownFds, O_CLOEXEC);
380 #else
381     int ret = pipe(caglobals.ip.shutdownFds);
382     if (-1 != ret)
383     {
384         ret = fcntl(caglobals.ip.shutdownFds[0], F_GETFD);
385         if (-1 != ret)
386         {
387             ret = fcntl(caglobals.ip.shutdownFds[0], F_SETFD, ret|FD_CLOEXEC);
388         }
389         if (-1 != ret)
390         {
391             ret = fcntl(caglobals.ip.shutdownFds[1], F_GETFD);
392         }
393         if (-1 != ret)
394         {
395             ret = fcntl(caglobals.ip.shutdownFds[1], F_SETFD, ret|FD_CLOEXEC);
396         }
397         if (-1 == ret)
398         {
399             close(caglobals.ip.shutdownFds[1]);
400             close(caglobals.ip.shutdownFds[0]);
401             caglobals.ip.shutdownFds[0] = -1;
402             caglobals.ip.shutdownFds[1] = -1;
403         }
404     }
405 #endif
406     if (-1 == ret)
407     {
408         OIC_LOG_V(ERROR, TAG, "pipe failed: %s", strerror(errno));
409         caglobals.ip.selectTimeout = SELECT_TIMEOUT; //poll needed for shutdown
410     }
411 }
412
413 CAResult_t CAIPStartServer(const ca_thread_pool_t threadPool)
414 {
415     CAResult_t res = CA_STATUS_OK;
416
417     if (caglobals.ip.started)
418     {
419         return res;
420     }
421
422     if (!IPv4MulticastAddress.s_addr)
423     {
424         (void)inet_aton(IPv4_MULTICAST, &IPv4MulticastAddress);
425         (void)inet_pton(AF_INET6, IPv6_MULTICAST_INT, &IPv6MulticastAddressInt);
426         (void)inet_pton(AF_INET6, IPv6_MULTICAST_LNK, &IPv6MulticastAddressLnk);
427         (void)inet_pton(AF_INET6, IPv6_MULTICAST_RLM, &IPv6MulticastAddressRlm);
428         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ADM, &IPv6MulticastAddressAdm);
429         (void)inet_pton(AF_INET6, IPv6_MULTICAST_SIT, &IPv6MulticastAddressSit);
430         (void)inet_pton(AF_INET6, IPv6_MULTICAST_ORG, &IPv6MulticastAddressOrg);
431         (void)inet_pton(AF_INET6, IPv6_MULTICAST_GLB, &IPv6MulticastAddressGlb);
432     }
433
434     if (!caglobals.ip.ipv6enabled && !caglobals.ip.ipv4enabled)
435     {
436         caglobals.ip.ipv4enabled = true;  // only needed to run CA tests
437     }
438
439     if (caglobals.ip.ipv6enabled)
440     {
441         NEWSOCKET(AF_INET6, u6)
442         NEWSOCKET(AF_INET6, u6s)
443         NEWSOCKET(AF_INET6, m6)
444         NEWSOCKET(AF_INET6, m6s)
445     }
446     if (caglobals.ip.ipv4enabled)
447     {
448         NEWSOCKET(AF_INET, u4)
449         NEWSOCKET(AF_INET, u4s)
450         NEWSOCKET(AF_INET, m4)
451         NEWSOCKET(AF_INET, m4s)
452     }
453
454     const char f[] = "socket summary: u6=%d, u6s=%d, u4=%d, u4s=%d, m6=%d, m6s=%d, m4=%d, m4s=%d";
455     OIC_LOG_V(DEBUG, TAG, f, caglobals.ip.u6.fd, caglobals.ip.u6s.fd,
456                              caglobals.ip.u4.fd, caglobals.ip.u4s.fd,
457                              caglobals.ip.m6.fd, caglobals.ip.m6s.fd,
458                              caglobals.ip.m4.fd, caglobals.ip.m4s.fd);
459     (void)f;    // eliminates release warning
460
461     // create pipe for fast shutdown
462     CAInitializePipe();
463     CHECKFD(caglobals.ip.shutdownFds[0]);
464     CHECKFD(caglobals.ip.shutdownFds[1]);
465
466     // create source of network interface change notifications
467     CAInitializeNetlink();
468
469     CAApplyInterfaces();
470
471     caglobals.ip.terminate = false;
472     res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
473     if (CA_STATUS_OK != res)
474     {
475         OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
476         return res;
477     }
478     OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
479
480     caglobals.ip.started = true;
481     return CA_STATUS_OK;
482 }
483
484 void CAIPStopServer()
485 {
486     OIC_LOG(DEBUG, TAG, "IN");
487
488     caglobals.ip.terminate = true;
489
490     if (caglobals.ip.shutdownFds[1] != -1)
491     {
492         close(caglobals.ip.shutdownFds[1]);
493         // receive thread will stop immediately
494     }
495     else
496     {
497         // receive thread will stop in SELECT_TIMEOUT seconds.
498     }
499
500     OIC_LOG(DEBUG, TAG, "OUT");
501 }
502
503 static void applyMulticastToInterface4(struct in_addr inaddr)
504 {
505     if (!caglobals.ip.ipv4enabled)
506     {
507         return;
508     }
509
510     struct ip_mreq mreq = { IPv4MulticastAddress };
511     mreq.imr_interface = inaddr;
512     if (setsockopt(caglobals.ip.m4.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
513     {
514         if (EADDRINUSE != errno)
515         {
516             OIC_LOG_V(ERROR, TAG, "IPv4 IP_ADD_MEMBERSHIP failed: %s", strerror(errno));
517         }
518     }
519     if (setsockopt(caglobals.ip.m4s.fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
520     {
521         if (EADDRINUSE != errno)
522         {
523             OIC_LOG_V(ERROR, TAG, "secure IPv4 IP_ADD_MEMBERSHIP failed: %s", strerror(errno));
524         }
525     }
526 }
527
528 static void applyMulticast6(int fd, struct in6_addr *addr, uint32_t interface)
529 {
530     struct ipv6_mreq mreq;
531     mreq.ipv6mr_multiaddr = *addr;
532     mreq.ipv6mr_interface = interface;
533     if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof (mreq)))
534     {
535         if (EADDRINUSE != errno)
536         {
537             OIC_LOG_V(ERROR, TAG, "IPv6 IP_ADD_MEMBERSHIP failed: %s", strerror(errno));
538         }
539     }
540 }
541
542 static void applyMulticastToInterface6(uint32_t interface)
543 {
544     if (!caglobals.ip.ipv6enabled)
545     {
546         return;
547     }
548     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressInt, interface);
549     applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressLnk, interface);
550     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressRlm, interface);
551     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressAdm, interface);
552     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressSit, interface);
553     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressOrg, interface);
554     //applyMulticast6(caglobals.ip.m6.fd, &IPv6MulticastAddressGlb, interface);
555     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressInt, interface);
556     applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressLnk, interface);
557     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressRlm, interface);
558     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressAdm, interface);
559     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressSit, interface);
560     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressOrg, interface);
561     //applyMulticast6(caglobals.ip.m6s.fd, &IPv6MulticastAddressGlb, interface);
562 }
563
564 static void CAApplyInterfaces()
565 {
566     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
567     if (!iflist)
568     {
569         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
570         return;
571     }
572
573     uint32_t len = u_arraylist_length(iflist);
574     OIC_LOG_V(DEBUG, TAG, "IP network interfaces found: %d", len);
575
576     for (uint32_t i = 0; i < len; i++)
577     {
578         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
579
580         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
581         {
582             continue;
583         }
584         if (ifitem->family == AF_INET)
585         {
586             struct in_addr inaddr;
587             inaddr.s_addr = ifitem->ipv4addr;
588             applyMulticastToInterface4(inaddr);
589             OIC_LOG_V(DEBUG, TAG, "IPv4 network interface: %s", ifitem->name);
590         }
591         if (ifitem->family == AF_INET6)
592         {
593             applyMulticastToInterface6(ifitem->index);
594             OIC_LOG_V(DEBUG, TAG, "IPv6 network interface: %s", ifitem->name);
595         }
596     }
597
598     u_arraylist_destroy(iflist);
599 }
600
601 static void CAHandleNetlink()
602 {
603 #ifdef __linux__
604 char buf[4096];
605 struct nlmsghdr *nh;
606 struct sockaddr_nl sa;
607 struct iovec iov = { buf, sizeof(buf) };
608 struct msghdr msg = { (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
609
610 int len = recvmsg(caglobals.ip.netlinkFd, &msg, 0);
611 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len))
612 {
613     if (nh->nlmsg_type == RTM_NEWLINK)
614     {
615         struct ifinfomsg *ifi = (struct ifinfomsg *)NLMSG_DATA(nh);
616         if ((ifi->ifi_flags & IFF_LOOPBACK) || !(ifi->ifi_flags & IFF_RUNNING))
617         {
618             continue;
619         }
620
621         int newIndex = ifi->ifi_index;
622
623         u_arraylist_t *iflist = CAIPGetInterfaceInformation(newIndex);
624         if (!iflist)
625         {
626             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
627             return;
628         }
629
630         uint32_t len = u_arraylist_length(iflist);
631         for (uint32_t i = 0; i < len; i++)
632         {
633             CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
634             if (ifitem->index != newIndex)
635             {
636                 continue;
637             }
638
639             applyMulticastToInterface6(newIndex);
640             struct in_addr inaddr;
641             inaddr.s_addr = ifitem->ipv4addr;
642             applyMulticastToInterface4(inaddr);
643             break;  // we found the one we were looking for
644         }
645         u_arraylist_destroy(iflist);
646     }
647 }
648 #endif // __linux__
649 }
650
651 void CAIPSetPacketReceiveCallback(CAIPPacketReceivedCallback callback)
652 {
653 OIC_LOG(DEBUG, TAG, "IN");
654
655 g_packetReceivedCallback = callback;
656
657 OIC_LOG(DEBUG, TAG, "OUT");
658 }
659
660 void CAIPSetExceptionCallback(CAIPExceptionCallback callback)
661 {
662 OIC_LOG(DEBUG, TAG, "IN");
663
664     g_exceptionCallback = callback;
665
666     OIC_LOG(DEBUG, TAG, "OUT");
667 }
668
669 static void sendData(int fd, const CAEndpoint_t *endpoint,
670                      const void *data, uint32_t dlen,
671                      const char *cast, const char *fam)
672 {
673     OIC_LOG(DEBUG, TAG, "IN");
674
675     char *secure = (endpoint->flags & CA_SECURE) ? "secure " : "";
676     (void)secure;   // eliminates release warning
677     struct sockaddr_storage sock;
678     CAConvertNameToAddr(endpoint->addr, endpoint->port, &sock);
679
680     if (sock.ss_family == AF_INET6)
681     {
682         struct sockaddr_in6 *sock6 = (struct sockaddr_in6 *)&sock;
683         if (!sock6->sin6_scope_id)
684         {
685             sock6->sin6_scope_id = endpoint->interface;
686         }
687     }
688
689     ssize_t len = sendto(fd, data, dlen, 0, (struct sockaddr *)&sock, sizeof (sock));
690     if (-1 == len)
691     {
692         OIC_LOG_V(ERROR, TAG, "%s%s %s sendTo failed: %s", secure, cast, fam, strerror(errno));
693     }
694     else
695     {
696         OIC_LOG_V(INFO, TAG, "%s%s %s sendTo is successful: %d bytes", secure, cast, fam, len);
697     }
698 }
699
700 static void sendMulticastData6(const u_arraylist_t *iflist,
701                                CAEndpoint_t *endpoint,
702                                const void *data, uint32_t datalen)
703 {
704     int scope = endpoint->flags & CA_SCOPE_MASK;
705     char *ipv6mcname = ipv6mcnames[scope];
706     if (!ipv6mcname)
707     {
708         OIC_LOG_V(INFO, TAG, "IPv6 multicast scope invalid: %d", scope);
709         return;
710     }
711     strncpy(endpoint->addr, ipv6mcname, MAX_ADDR_STR_SIZE_CA);
712     int fd = caglobals.ip.u6.fd;
713
714     uint32_t len = u_arraylist_length(iflist);
715     for (uint32_t i = 0; i < len; i++)
716     {
717         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
718         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
719         {
720             continue;
721         }
722         if (ifitem->family != AF_INET6)
723         {
724             continue;
725         }
726
727         int index = ifitem->index;
728         if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, sizeof (index)))
729         {
730             OIC_LOG_V(ERROR, TAG, "setsockopt6 failed: %s", strerror(errno));
731             return;
732         }
733         sendData(fd, endpoint, data, datalen, "multicast", "ipv6");
734     }
735 }
736
737 static void sendMulticastData4(const u_arraylist_t *iflist,
738                                CAEndpoint_t *endpoint,
739                                const void *data, uint32_t datalen)
740 {
741     struct ip_mreq mreq = { IPv4MulticastAddress };
742     strncpy(endpoint->addr, IPv4_MULTICAST, MAX_ADDR_STR_SIZE_CA);
743     int fd = caglobals.ip.u4.fd;
744
745     uint32_t len = u_arraylist_length(iflist);
746     for (uint32_t i = 0; i < len; i++)
747     {
748         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
749         if ((ifitem->flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
750         {
751             continue;
752         }
753         if (ifitem->family != AF_INET)
754         {
755             continue;
756         }
757
758         struct in_addr inaddr;
759         inaddr.s_addr = ifitem->ipv4addr;
760         mreq.imr_interface = inaddr;
761         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof (mreq)))
762         {
763             OIC_LOG_V(ERROR, TAG, "send IP_MULTICAST_IF failed: %s (using defualt)", strerror(errno));
764         }
765         sendData(fd, endpoint, data, datalen, "multicast", "ipv4");
766     }
767 }
768
769 void CAIPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
770                                                             bool isMulticast)
771 {
772     VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
773     VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
774
775     bool isSecure = (endpoint->flags & CA_SECURE) != 0;
776
777     if (isMulticast)
778     {
779         endpoint->port = isSecure ? CA_SECURE_COAP : CA_COAP;
780
781         u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
782         if (!iflist)
783         {
784             OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
785             return;
786         }
787
788         if ((endpoint->flags & CA_IPV6) && caglobals.ip.ipv6enabled)
789         {
790             sendMulticastData6(iflist, endpoint, data, datalen);
791         }
792         if ((endpoint->flags & CA_IPV4) && caglobals.ip.ipv4enabled)
793         {
794             sendMulticastData4(iflist, endpoint, data, datalen);
795         }
796
797         u_arraylist_destroy(iflist);
798     }
799     else
800     {
801         int fd;
802         if (endpoint->flags & CA_IPV6)
803         {
804             fd = isSecure ? caglobals.ip.u6s.fd : caglobals.ip.u6.fd;
805             #ifndef __WITH_DTLS__
806             fd = caglobals.ip.u6.fd;
807             #endif
808             sendData(fd, endpoint, data, datalen, "unicast", "ipv6");
809         }
810         if (endpoint->flags & CA_IPV4)
811         {
812             fd = isSecure ? caglobals.ip.u4s.fd : caglobals.ip.u4.fd;
813             #ifndef __WITH_DTLS__
814             fd = caglobals.ip.u4.fd;
815             #endif
816             sendData(fd, endpoint, data, datalen, "unicast", "ipv4");
817         }
818     }
819 }
820
821 CAResult_t CAGetIPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
822 {
823     OIC_LOG(DEBUG, TAG, "IN");
824
825     VERIFY_NON_NULL(info, TAG, "info is NULL");
826     VERIFY_NON_NULL(size, TAG, "size is NULL");
827
828     u_arraylist_t *iflist = CAIPGetInterfaceInformation(0);
829     if (!iflist)
830     {
831         OIC_LOG_V(ERROR, TAG, "get interface info failed: %s", strerror(errno));
832         return CA_STATUS_FAILED;
833     }
834
835     uint32_t len = u_arraylist_length(iflist);
836
837     CAEndpoint_t *eps = (CAEndpoint_t *)OICCalloc(len, sizeof (CAEndpoint_t));
838     if (!eps)
839     {
840         OIC_LOG(ERROR, TAG, "Malloc Failed");
841         u_arraylist_destroy(iflist);
842         return CA_MEMORY_ALLOC_FAILED;
843     }
844
845     for (uint32_t i = 0, j = 0; i < len; i++)
846     {
847         CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i);
848
849         OICStrcpy(eps[j].addr, CA_INTERFACE_NAME_SIZE, ifitem->name);
850         eps[j].flags = ifitem->family == AF_INET6 ? CA_IPV6 : CA_IPV4;
851         eps[j].adapter = CA_ADAPTER_IP;
852         eps[j].interface = 0;
853         eps[j].port = 0;
854         j++;
855     }
856
857     *info = eps;
858     *size = len;
859
860     u_arraylist_destroy(iflist);
861
862     OIC_LOG(DEBUG, TAG, "OUT");
863     return CA_STATUS_OK;
864 }
865