diff --git a/include/ifaddrs.h b/include/ifaddrs.h new file mode 100644 index 0000000000..286ace2d6b --- /dev/null +++ b/include/ifaddrs.h @@ -0,0 +1,73 @@ +/**************************************************************************** + * include/ifaddrs.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_IFADDRS_H +#define __INCLUDE_IFADDRS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ +#endif + +/**************************************************************************** + * Public Type Definitions + ****************************************************************************/ + +struct ifaddrs +{ + FAR struct ifaddrs *ifa_next; + FAR char *ifa_name; + unsigned int ifa_flags; + FAR struct sockaddr *ifa_addr; + FAR struct sockaddr *ifa_netmask; + FAR struct sockaddr *ifa_dstaddr; + FAR void *ifa_data; +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +extern int getifaddrs(FAR struct ifaddrs **addrs); +extern void freeifaddrs(FAR struct ifaddrs *addrs); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __INCLUDE_IFADDRS_H */ diff --git a/libs/libc/net/Make.defs b/libs/libc/net/Make.defs index 10aed949be..6a51876ef7 100644 --- a/libs/libc/net/Make.defs +++ b/libs/libc/net/Make.defs @@ -34,6 +34,7 @@ CSRCS += lib_loopback.c endif ifeq ($(CONFIG_NETDEV_IFINDEX),y) +CSRCS += lib_getifaddrs.c lib_freeifaddrs.c CSRCS += lib_indextoname.c lib_nametoindex.c CSRCS += lib_nameindex.c lib_freenameindex.c endif diff --git a/libs/libc/net/lib_freeifaddrs.c b/libs/libc/net/lib_freeifaddrs.c new file mode 100644 index 0000000000..2e68969e7f --- /dev/null +++ b/libs/libc/net/lib_freeifaddrs.c @@ -0,0 +1,56 @@ +/**************************************************************************** + * libs/libc/net/lib_freeifaddrs.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "libc.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: freeifaddrs + * + * Description: + * The freeifaddrs() function frees the data structure returned by + * getifaddrs(). + * + * Input Parameters: + * addrs - The data structure to free + * + * Returned Value: + * None + * + ****************************************************************************/ + +void freeifaddrs(FAR struct ifaddrs *addrs) +{ + while (addrs != NULL) + { + FAR struct ifaddrs *tmp = addrs; + addrs = addrs->ifa_next; + lib_free(tmp); + } +} diff --git a/libs/libc/net/lib_getifaddrs.c b/libs/libc/net/lib_getifaddrs.c new file mode 100644 index 0000000000..0e17cd4fa6 --- /dev/null +++ b/libs/libc/net/lib_getifaddrs.c @@ -0,0 +1,282 @@ +/**************************************************************************** + * libs/libc/net/lib_getifaddrs.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#include "libc.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#undef broadaddr +#define broadaddr dstaddr + +/**************************************************************************** + * Private Type Definitions + ****************************************************************************/ + +struct myifaddrs +{ + struct ifaddrs addrs; + char name[IF_NAMESIZE]; + struct sockaddr_storage addr; + struct sockaddr_storage netmask; + struct sockaddr_storage dstaddr; + struct sockaddr hwaddr; +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: getifaddrs + * + * Description: + * The getifaddrs() function returns a linked list of ifaddrs structures, + * each containing information about one of the network interfaces on the + * local system. The ifaddrs structure contains at least the following + * entries: + * struct ifaddrs *ifa_next; + * char *ifa_name; + * unsigned int ifa_flags; + * struct sockaddr *ifa_addr; + * struct sockaddr *ifa_netmask; + * struct sockaddr *ifa_dstaddr; + * void *ifa_data; + * The ifa_next field contains a pointer to the next structure on + * the list, or NULL if this is the last item of the list. + * + * The ifa_name points to the null-terminated interface name. + * + * The ifa_flags field contains the interface flags, as returned by + * the SIOCGIFFLAGS ioctl(2) operation (see netdevice(7) for a list + * of these flags). + * + * The ifa_addr field points to a structure containing the interface + * address. (The sa_family subfield should be consulted to + * determine the format of the address structure.) This field may + * contain a null pointer. + * + * The ifa_netmask field points to a structure containing the + * netmask associated with ifa_addr, if applicable for the address + * family. This field may contain a null pointer. + * + * Depending on whether the bit IFF_BROADCAST or IFF_POINTOPOINT is + * set in ifa_flags (only one can be set at a time), either + * ifa_broadaddr will contain the broadcast address associated with + * ifa_addr (if applicable for the address family) or ifa_dstaddr + * will contain the destination address of the point-to-point + * interface. + * + * The ifa_data field points to a buffer containing address-family- + * specific data; this field may be NULL if there is no such data + * for this interface. + * + * Input Parameters: + * None + * + * Returned Value: + * On success, getifaddrs() returns pointer to the linked list; on error, + * NULL is returned, and errno is set to indicate the error. + * + ****************************************************************************/ + +int getifaddrs(FAR struct ifaddrs **addrs) +{ + FAR struct myifaddrs *myaddrs = NULL; + int sockfd; + int i; + + if (addrs == NULL) + { + set_errno(EINVAL); + return ERROR; + } + + sockfd = socket(NET_SOCK_FAMILY, NET_SOCK_TYPE, NET_SOCK_PROTOCOL); + if (sockfd < 0) + { + return sockfd; + } + + for (i = 1, *addrs = NULL; i <= MAX_IFINDEX; i++) + { + unsigned int flags; + struct lifreq req; + + memset(&req, 0, sizeof(req)); + req.lifr_ifindex = i; + + if (ioctl(sockfd, SIOCGIFNAME, (unsigned long)&req) < 0) + { + continue; /* Empty slot, try next one */ + } + + if (ioctl(sockfd, SIOCGIFFLAGS, (unsigned long)&req) < 0) + { + goto err; + } + + flags = req.lifr_flags; + + if (myaddrs != NULL) + { + myaddrs->addrs.ifa_next = lib_zalloc(sizeof(*myaddrs)); + myaddrs = (FAR struct myifaddrs *)myaddrs->addrs.ifa_next; + } + else + { + *addrs = lib_zalloc(sizeof(*myaddrs)); + myaddrs = (FAR struct myifaddrs *)*addrs; + } + + if (myaddrs == NULL) + { + goto err; + } + + myaddrs->addrs.ifa_name = myaddrs->name; + strncpy(myaddrs->name, req.lifr_name, IF_NAMESIZE); + + myaddrs->addrs.ifa_flags = flags; + +#ifdef CONFIG_NET_IPv4 + if (ioctl(sockfd, SIOCGIFADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_addr = (FAR struct sockaddr *)&myaddrs->addr; + memcpy(&myaddrs->addr, &req.lifr_addr, sizeof(req.lifr_addr)); + + if (ioctl(sockfd, SIOCGIFNETMASK, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_netmask = + (FAR struct sockaddr *)&myaddrs->netmask; + memcpy(&myaddrs->netmask, + &req.lifr_netmask, sizeof(req.lifr_netmask)); + } + + if (ioctl(sockfd, SIOCGIFDSTADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_dstaddr = + (FAR struct sockaddr *)&myaddrs->dstaddr; + memcpy(&myaddrs->dstaddr, + &req.lifr_dstaddr, sizeof(req.lifr_dstaddr)); + } + else if (ioctl(sockfd, SIOCGIFBRDADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_broadaddr = + (FAR struct sockaddr *)&myaddrs->broadaddr; + memcpy(&myaddrs->broadaddr, + &req.lifr_broadaddr, sizeof(req.lifr_broadaddr)); + } + + if (ioctl(sockfd, SIOCGIFHWADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_data = &myaddrs->hwaddr; + memcpy(&myaddrs->hwaddr, + &req.lifr_hwaddr, sizeof(req.lifr_hwaddr)); + } + } +#endif + +#ifdef CONFIG_NET_IPv6 + if (ioctl(sockfd, SIOCGLIFADDR, (unsigned long)&req) >= 0) + { + /* Has IPv4 entry ? */ + + if (myaddrs->addrs.ifa_addr) + { + /* Yes, allocate the new entry for IPv6 */ + + myaddrs->addrs.ifa_next = lib_zalloc(sizeof(*myaddrs)); + myaddrs = (FAR struct myifaddrs *)myaddrs->addrs.ifa_next; + + if (myaddrs == NULL) + { + goto err; + } + + myaddrs->addrs.ifa_name = myaddrs->name; + strncpy(myaddrs->name, req.lifr_name, IF_NAMESIZE); + + myaddrs->addrs.ifa_flags = flags; + } + + myaddrs->addrs.ifa_addr = (FAR struct sockaddr *)&myaddrs->addr; + memcpy(&myaddrs->addr, &req.lifr_addr, sizeof(req.lifr_addr)); + + if (ioctl(sockfd, SIOCGLIFNETMASK, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_netmask = + (FAR struct sockaddr *)&myaddrs->netmask; + memcpy(&myaddrs->netmask, + &req.lifr_netmask, sizeof(req.lifr_netmask)); + } + + if (ioctl(sockfd, SIOCGLIFDSTADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_dstaddr = + (FAR struct sockaddr *)&myaddrs->dstaddr; + memcpy(&myaddrs->dstaddr, + &req.lifr_dstaddr, sizeof(req.lifr_dstaddr)); + } + else if (ioctl(sockfd, SIOCGLIFBRDADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_broadaddr = + (FAR struct sockaddr *)&myaddrs->broadaddr; + memcpy(&myaddrs->broadaddr, + &req.lifr_broadaddr, sizeof(req.lifr_broadaddr)); + } + + if (ioctl(sockfd, SIOCGIFHWADDR, (unsigned long)&req) >= 0) + { + myaddrs->addrs.ifa_data = &myaddrs->hwaddr; + memcpy(&myaddrs->hwaddr, + &req.lifr_hwaddr, sizeof(req.lifr_hwaddr)); + } + } +#endif + } + + close(sockfd); + return OK; + +err: + if (*addrs != NULL) + { + freeifaddrs(*addrs); + *addrs = NULL; + } + + close(sockfd); + return ERROR; +}