[IOT-1528]update file path and remove static analysis warring
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ip_adapter / android / caifaddrs.c
1 /******************************************************************
2 *
3 * Copyright 2016 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 "caifaddrs.h"
22
23 #include <stdbool.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/socket.h>
29 #include <net/if_arp.h>
30 #include <netinet/in.h>
31 #include <linux/netlink.h>
32 #include <linux/rtnetlink.h>
33 #include "logger.h"
34 #define TAG "OIC_CA_ifaddrs"
35
36 #define NETLINK_MESSAGE_LENGTH  (4096)
37 #define IFC_LABEL_LOOP          "lo"
38 #define IFC_ADDR_LOOP_IPV4      "127.0.0.1"
39 #define IFC_ADDR_LOOP_IPV6      "::1"
40
41 typedef struct {
42     struct nlmsghdr     msgInfo;
43     struct ifaddrmsg    ifaddrInfo;
44 } CANetlintReq_t;
45
46
47 static bool CASendNetlinkMessage(int netlinkFd, const void* data, size_t len)
48 {
49     ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(netlinkFd, data, len, 0));
50     return (sentByteCount == (ssize_t)(len));
51 }
52
53 void CAFreeIfAddrs(struct ifaddrs *ifa)
54 {
55     struct ifaddrs *cur;
56     while (ifa)
57     {
58         cur = ifa;
59         ifa = ifa->ifa_next;
60         free(cur);
61     }
62 }
63
64 static struct ifaddrs *CAParsingAddr(struct nlmsghdr *recvMsg)
65 {
66     struct ifaddrmsg *ifaddrmsgData = (struct ifaddrmsg*)NLMSG_DATA(recvMsg);
67     if (ifaddrmsgData-> ifa_family != AF_INET && ifaddrmsgData-> ifa_family != AF_INET6)
68     {
69         return NULL;
70     }
71
72     struct rtattr *rtattrData = (struct rtattr*)IFA_RTA(ifaddrmsgData);
73     int ifaddrmsgLen = IFA_PAYLOAD(recvMsg);
74
75     struct ifaddrs *node = (struct ifaddrs *)OICCalloc(1, sizeof(struct ifaddrs));
76     char nameBuf[IFNAMSIZ] = { 0 };
77     node->ifa_next = NULL;
78     if_indextoname(ifaddrmsgData->ifa_index, nameBuf);
79     node->ifa_name = (char *)OICCalloc(strlen(nameBuf)+1, sizeof(char));
80     OICStrcpy(node->ifa_name, strlen(nameBuf)+1, nameBuf);
81     node->ifa_flags = ifaddrmsgData->ifa_flags;
82     node->ifa_flags |= (IFF_UP|IFF_RUNNING);
83     void *dest = NULL;
84     struct sockaddr_storage* ss = NULL;
85
86     for (; RTA_OK(rtattrData, ifaddrmsgLen); rtattrData = RTA_NEXT(rtattrData, ifaddrmsgLen))
87     {
88         switch (rtattrData->rta_type)
89         {
90             case IFA_ADDRESS:
91                 ss = (struct sockaddr_storage*)OICCalloc(1, sizeof(struct sockaddr_storage));
92                 ss->ss_family = ifaddrmsgData-> ifa_family;
93
94                 if (ifaddrmsgData-> ifa_family == AF_INET)
95                 {
96                     dest = &((struct sockaddr_in*)ss)->sin_addr;
97                     memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
98                 }
99                 else if (ifaddrmsgData-> ifa_family == AF_INET6)
100                 {
101                     dest = &((struct sockaddr_in6*)ss)->sin6_addr;
102                     memcpy(dest, RTA_DATA(rtattrData), RTA_PAYLOAD(rtattrData));
103                 }
104
105                 node->ifa_addr = (struct sockaddr*)ss;
106                 break;
107
108             default :
109                 // do nothing
110                 break;
111         }
112     }
113
114     return node;
115 }
116
117 CAResult_t CAGetIfaddrsUsingNetlink(struct ifaddrs **ifap)
118 {
119     if (!ifap)
120     {
121         OIC_LOG(ERROR, TAG, "netlink argument error");
122         return CA_STATUS_INVALID_PARAM;
123     }
124     *ifap = NULL;
125
126     int netlinkFd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
127     int state = -1;
128     if (-1 == netlinkFd)
129     {
130         OIC_LOG_V(ERROR, TAG, "netlink socket failed: %s", strerror(errno));
131         return CA_SOCKET_OPERATION_FAILED;
132     }
133
134     // send request to kernel
135     CANetlintReq_t req;
136     memset(&req, 0, sizeof(req));
137     req.msgInfo.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req)));
138     req.msgInfo.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
139     req.msgInfo.nlmsg_type = RTM_GETADDR;
140     req.ifaddrInfo.ifa_family = AF_UNSPEC;
141     req.ifaddrInfo.ifa_index = 0;
142
143     if (!CASendNetlinkMessage(netlinkFd, &req, req.msgInfo.nlmsg_len))
144     {
145         OIC_LOG(ERROR, TAG, "netlink send failed");
146         goto exit;
147     }
148
149     while (1)
150     {
151         char recvBuf[NETLINK_MESSAGE_LENGTH] = {0};
152         struct nlmsghdr *recvMsg = NULL;
153         struct ifaddrs *node = NULL;
154         struct sockaddr_nl sa = { .nl_family = 0 };
155         struct iovec iov = { .iov_base = recvBuf,
156                          .iov_len = sizeof (recvBuf) };
157
158         struct msghdr msg = { .msg_name = (void *)&sa,
159                           .msg_namelen = sizeof (sa),
160                           .msg_iov = &iov,
161                           .msg_iovlen = 1 };
162
163         ssize_t len = recvmsg(netlinkFd, &msg, 0);
164
165         for (recvMsg = (struct nlmsghdr *)recvBuf; NLMSG_OK(recvMsg, len);
166              recvMsg = NLMSG_NEXT(recvMsg, len))
167         {
168             switch (recvMsg->nlmsg_type)
169             {
170                 case NLMSG_DONE:
171                     OIC_LOG(DEBUG, TAG, "NLMSG_DONE");
172                     state = 0;
173                     goto exit;
174
175                 case NLMSG_ERROR:
176                     OIC_LOG(ERROR, TAG, "NLMSG is invalid");
177                     state = -1;
178                     goto exit;
179
180                 case RTM_NEWADDR:
181                     OIC_LOG(DEBUG, TAG, "RTM_NEWADDR");
182                     node = CAParsingAddr(recvMsg);
183
184                     if (*ifap == NULL)
185                     {
186                         *ifap = node;
187                     }
188                     else
189                     {
190                         node->ifa_next = *ifap;
191                         *ifap = node;
192                     }
193
194                     break;
195
196                 case RTM_NEWLINK:
197                 default:
198                     OIC_LOG(DEBUG, TAG, "ignore unknown NLMSG");
199                     break;
200             }
201         }
202     }
203
204
205 exit:
206     // release all resources
207     close(netlinkFd);
208     if (state == -1)
209     {
210         CAFreeIfAddrs(*ifap);
211         return CA_SOCKET_OPERATION_FAILED;
212     }
213     return CA_STATUS_OK;
214 }