summaryrefslogtreecommitdiffstats
path: root/common/elapi/elapi_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/elapi/elapi_ioctl.c')
-rw-r--r--common/elapi/elapi_ioctl.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/common/elapi/elapi_ioctl.c b/common/elapi/elapi_ioctl.c
new file mode 100644
index 000000000..c2a42a17c
--- /dev/null
+++ b/common/elapi/elapi_ioctl.c
@@ -0,0 +1,142 @@
+/*
+ ELAPI
+
+ Special platform specific functions related to networking
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "elapi_ioctl.h"
+#include "trace.h"
+#include "config.h"
+
+#ifndef HAVE_GETIFADDRS
+
+/* These functions are taken form Stevens's
+ * UNIX Network Programming Volume 1
+ */
+
+int elapi_get_addrlist(struct ifconf *ifc)
+{
+ int sockfd;
+ int length, lastlen;
+ int error;
+ char *buffer;
+
+ TRACE_FLOW_STRING("elapi_get_addrlist", "Entry");
+
+ /* Open socket */
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ lastlen = 0;
+ length = INTERFACE_NUM_GUESS * sizeof(struct ifreq);
+
+ /* Allocate right amount of memory */
+ /* This is a trick from Stevens book */
+ /* Search web for "get_ifi_info" to get original code */
+ for ( ; ; ) {
+
+ buffer = malloc(length);
+ ifc->ifc_len = length;
+ ifc->ifc_buf = buffer;
+
+ /* Read list */
+ if (ioctl(sockfd, SIOCGIFCONF, ifc) < 0) {
+ error = errno;
+ TRACE_INFO_NUMBER("Ioctl call failed", error);
+ if (error != EINVAL || lastlen != 0) {
+ free(buffer);
+ TRACE_ERROR_NUMBER("ioctl failed", error);
+ return error;
+ }
+ } else {
+ TRACE_INFO_NUMBER("Length returned", ifc->ifc_len);
+ TRACE_INFO_NUMBER("Previous length", lastlen);
+ /* Break if length is same */
+ if (ifc->ifc_len == lastlen) break;
+ lastlen = ifc->ifc_len;
+ }
+
+ /* Grow length */
+ length += INTERFACE_NUM_INC * sizeof(struct ifreq);
+ free(buffer);
+ }
+
+ TRACE_FLOW_STRING("elapi_get_addrlist", "Exit");
+ return EOK;
+}
+
+/* Get the variable part of the size of the address */
+static int elapi_get_addrlen(struct ifreq *ifr)
+{
+ int len;
+
+ TRACE_FLOW_STRING("elapi_get_addrlen", "Entry");
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+ len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
+#else
+ switch (ifr->ifr_addr.sa_family) {
+#ifdef IPV6
+ case AF_INET6:
+ len = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case AF_INET:
+ default:
+ len = sizeof(struct sockaddr);
+ break;
+ }
+#endif /* HAVE_SOCKADDR_SA_LEN */
+
+ TRACE_FLOW_NUMBER("elapi_get_addrlen Returning", len);
+ return len;
+}
+
+/* Get next address */
+struct ifreq *elapi_get_next_addr(struct ifconf *ifc, struct ifreq *current)
+{
+ char *ifr;
+
+ TRACE_FLOW_STRING("elapi_get_next_addr", "Entry");
+
+ TRACE_INFO_NUMBER("Current ifi", current);
+ TRACE_INFO_NUMBER("Address", &current->ifr_addr);
+
+ /* Move to the next item */
+ ifr = (char *)current + sizeof(current->ifr_name) + elapi_get_addrlen(current);
+
+ TRACE_INFO_NUMBER("New ifi", ifr);
+
+ /* Check if we are beyond the end of the allocated area */
+ /* Have to cast otherwise get warnings */
+ if (ifr >= ((char *)ifc->ifc_buf + ifc->ifc_len)) ifr = NULL;
+
+ TRACE_INFO_NUMBER("New ifi adjusted", ifr);
+
+ TRACE_FLOW_STRING("elapi_get_next_addr", "Exit");
+
+ return (struct ifreq *)ifr;
+}
+
+
+#endif /* HAVE_GETIFADDRS */