$OpenBSD: patch-opal_util_if_c,v 1.1 2010/03/21 10:45:19 jasper Exp $

Rewrite network interface configuration using getifaddrs(3) for BSD.
From NetBSD's patch-ah.

--- opal/util/if.c.orig	Tue Dec  8 21:36:09 2009
+++ opal/util/if.c	Thu Feb  4 13:59:49 2010
@@ -38,7 +38,10 @@
 #endif
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#if defined(__DragonFly__)
+#define IN_LINKLOCAL(i)        (((u_int32_t)(i) & 0xffff0000) == 0xa9fe0000)
 #endif
+#endif
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
@@ -164,6 +167,145 @@ static int opal_ifinit(void) 
                                 false, false, (int)false, &sd);
     do_not_resolve = OPAL_INT_TO_BOOL(sd);
 
+#if defined(__NetBSD__) || defined(__FreeBSD__) || \
+    defined(__OpenBSD__) || defined(__DragonFly__)
+    /* configure using getifaddrs(3) */
+    {
+        OBJ_CONSTRUCT(&opal_if_list, opal_list_t);
+
+        struct ifaddrs **ifadd_list;
+        struct ifaddrs *cur_ifaddrs;
+        struct sockaddr_in* sin_addr;
+
+        /* 
+         * the manpage claims that getifaddrs() allocates the memory,
+         * and freeifaddrs() is later used to release the allocated memory.
+         * however, without this malloc the call to getifaddrs() segfaults
+         */
+        ifadd_list = (struct ifaddrs **) malloc(sizeof(struct ifaddrs*));
+
+        /* create the linked list of ifaddrs structs */
+        if(getifaddrs(ifadd_list) < 0) {
+            opal_output(0, "opal_ifinit: getifaddrs() failed with error=%d\n",
+                    errno);
+            return OPAL_ERROR;
+        }
+
+        for(cur_ifaddrs = *ifadd_list; NULL != cur_ifaddrs; 
+                cur_ifaddrs = cur_ifaddrs->ifa_next) {
+
+            opal_if_t intf;
+            opal_if_t *intf_ptr;
+            struct in_addr a4;
+
+#if 0
+	    printf("interface %s.\n", cur_ifaddrs->ifa_name);
+#endif
+            /* skip non- af_inet interface addresses */
+            if(AF_INET != cur_ifaddrs->ifa_addr->sa_family) {
+#if 0
+	      printf("skipping non- af_inet interface %s, family %d.\n",
+		     cur_ifaddrs->ifa_name, cur_ifaddrs->ifa_addr->sa_family);
+#endif
+		continue;
+	    }
+
+            /* skip interface if it is down (IFF_UP not set) */
+            if(0 == (cur_ifaddrs->ifa_flags & IFF_UP)) {
+#if 0
+                printf("skipping non-up interface %s.\n", cur_ifaddrs->ifa_name);
+#endif
+                continue;
+            }
+
+            /* skip interface if it is a loopback device (IFF_LOOPBACK set) */
+            /* or if it is a point-to-point interface */
+            /* TODO: do we really skip p2p? */
+            if(0 != (cur_ifaddrs->ifa_flags & IFF_LOOPBACK)
+                    || 0!= (cur_ifaddrs->ifa_flags & IFF_POINTOPOINT)) {
+#if 0
+                printf("skipping loopback interface %s.\n", cur_ifaddrs->ifa_name);
+#endif              
+                continue;
+            }
+
+#if 0
+	    printf("sa_len %d.\n", cur_ifaddrs->ifa_addr->sa_len);
+#endif
+            sin_addr = (struct sockaddr_in *) cur_ifaddrs->ifa_addr;
+
+	    /* Do we really need to skip link-local addresses? */
+#if 0
+            /* skip link local address: */
+            if(IN_LINKLOCAL (htonl(((struct sockaddr_in*)cur_ifaddrs->ifa_addr)->sin_addr.s_addr))) {
+#if 0
+                opal_output(0, "opal_ifinit: skipping link-local ip address on interface %s.\n",
+                        cur_ifaddrs->ifa_name);
+#endif
+                continue;
+            }
+#endif
+
+            memset(&intf, 0, sizeof(intf));
+            OBJ_CONSTRUCT(&intf, opal_list_item_t);
+#if 0 
+            char *addr_name = (char *) malloc(48*sizeof(char));
+            inet_ntop(AF_INET, &sin_addr->sin_addr, addr_name, 48*sizeof(char));
+            opal_output(0, "inet capable interface %s discovered, address %s.\n", 
+                    cur_ifaddrs->ifa_name, addr_name);
+            free(addr_name);
+#endif
+
+            /* fill values into the opal_if_t */
+            memcpy(&a4, &(sin_addr->sin_addr), sizeof(struct in_addr));
+            
+            strncpy(intf.if_name, cur_ifaddrs->ifa_name, IF_NAMESIZE);
+            intf.if_index = opal_list_get_size(&opal_if_list) + 1;
+            ((struct sockaddr_in*) &intf.if_addr)->sin_addr = a4;
+            ((struct sockaddr_in*) &intf.if_addr)->sin_family = AF_INET;
+            ((struct sockaddr_in*) &intf.if_addr)->sin_len =  cur_ifaddrs->ifa_addr->sa_len;
+
+            /* since every scope != 0 is ignored, we just set the scope to 0 */
+            /* There's no scope_id in the non-ipv6 stuff 
+	    ((struct sockaddr_in6*) &intf.if_addr)->sin6_scope_id = 0; 
+	    */
+
+            /*
+             * hardcoded netmask, adrian says that's ok
+             */
+	    /* Non-NetBSD uses intf.if_mask = prefix(((struct sockaddr_in*) &ifr->ifr_addr)->sin_addr.s_addr); */
+            /* intf.if_mask = 64; */
+	    intf.if_mask = prefix( sin_addr->sin_addr.s_addr);
+            intf.if_flags = cur_ifaddrs->ifa_flags;
+
+            /*
+             * FIXME: figure out how to gain access to the kernel index
+             * (or create our own), getifaddrs() does not contain such
+             * data
+             */
+
+            intf.if_kernel_index = (uint16_t) if_nametoindex(cur_ifaddrs->ifa_name);
+
+            intf_ptr = (opal_if_t*) calloc(1, sizeof(opal_if_t));
+            if(NULL == intf_ptr) {
+                opal_output(0, "opal_ifinit: unable to allocate %lu bytes\n",
+                            sizeof(opal_if_t));
+                OBJ_DESTRUCT(&intf);
+                return OPAL_ERR_OUT_OF_RESOURCE;
+            }
+            memcpy(intf_ptr, &intf, sizeof(intf));
+
+#if 0
+            printf("About to append interface %s.\n", cur_ifaddrs->ifa_name);
+#endif
+	    /* opal_list_append(&opal_if_list, &intf_ptr->super); */
+            opal_list_append(&opal_if_list, (opal_list_item_t*) intf_ptr);
+
+            OBJ_DESTRUCT(&intf);
+        }   /*  of for loop over ifaddrs list */
+
+    }
+#else
     /* create the internet socket to test off */
 /*
    Change AF_INET to AF_UNSPEC (or AF_INET6) and everything will fail.
@@ -356,6 +498,10 @@ static int opal_ifinit(void) 
     }
     free(ifconf.ifc_req);
     close(sd);
+
+#endif /* anything other than {Net,Open,Free}BSD and DragonFly */
+
+
 #if OPAL_WANT_IPV6
 #ifdef __linux__ /* Linux does not have SIOCGL*, so parse
                      /proc/net/if_inet6 instead */
