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