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