getifaddrs: implement proper ipv6 netmasks
[musl] / src / network / getifaddrs.c
index c736263..a4c3178 100644 (file)
@@ -36,7 +36,6 @@ static stor* list_add(stor** list, stor** head, char* ifname)
                *head = curr;
                if(!*list) *list = curr;
        }
-       out:
        return curr;
 }
 
@@ -52,8 +51,17 @@ void freeifaddrs(struct ifaddrs *ifp)
 
 static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
 {
-       // FIXME: left for bit-wizard rich
-       memset(&sa->sin6_addr, -1, sizeof(sa->sin6_addr));
+       unsigned char* hb = sa->sin6_addr.s6_addr;
+       unsigned onebytes = prefix_length / 8;
+       unsigned bits = prefix_length % 8;
+       unsigned nullbytes = 16 - onebytes;
+       memset(hb, -1, onebytes);
+       memset(hb+onebytes, 0, nullbytes);
+       if(bits) {
+               unsigned char x = -1;
+               x <<= 8 - bits;
+               hb[onebytes] = x;
+       }
 }
 
 static void dealwithipv6(stor **list, stor** head)
@@ -106,31 +114,18 @@ static void dealwithipv6(stor **list, stor** head)
 
 int getifaddrs(struct ifaddrs **ifap)
 {
-       FILE* f = fopen("/proc/net/dev", "r");
-       if(!f) return -1;
-
-       /* the alternative to parsing /proc.. seems to be iterating
-          through the interfaces using an index number in ifreq.ifr_ifindex
-          until we get some error code back. the kernel will fill ifr_name field
-          for valid ifindices (SIOCGIFINDEX) */
        stor *list = 0, *head = 0;
-
-       char* line; char linebuf[512];
-       while((line = fgets(linebuf, sizeof linebuf, f))) {
-               while(isspace(*line) && *line) line++;
-               char* start = line;
-               while(*line && isalnum(*line)) line++;
-               if(line > start && *line == ':') {
-                       // found interface
-                       *line = 0;
-                       stor* curr = list_add(&list, &head, start);
-                       if(!curr) {
-                               fclose(f);
-                               goto err2;
-                       }
+       struct if_nameindex* ii = if_nameindex();
+       if(!ii) return -1;
+       size_t i;
+       for(i = 0; ii[i].if_index || ii[i].if_name; i++) {
+               stor* curr = list_add(&list, &head, ii[i].if_name);
+               if(!curr) {
+                       if_freenameindex(ii);
+                       goto err2;
                }
        }
-       fclose(f);
+       if_freenameindex(ii);
 
        int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
        if(sock == -1) goto err2;
@@ -139,7 +134,6 @@ int getifaddrs(struct ifaddrs **ifap)
        if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;
        size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
        for(head = list; head; head = (stor*)head->next) {
-               size_t i;
                for(i = 0; i < reqitems; i++) {
                        // get SIOCGIFADDR of active interfaces.
                        if(!strcmp(reqs[i].ifr_name, head->name)) {