|  | #include <u.h> | 
|  | /* #include <everything_but_the_kitchen_sink.h> */ | 
|  | #include <sys/socket.h> | 
|  | #include <netinet/in.h> | 
|  | #include <net/if.h> | 
|  | #include <sys/ioctl.h> | 
|  | #include <sys/sysctl.h> | 
|  | #include <net/ethernet.h> | 
|  | #include <net/if.h> | 
|  | #include <net/if_var.h> | 
|  | #include <net/if_dl.h> | 
|  | #include <net/if_types.h> | 
|  | #include <net/route.h> | 
|  | #include <netinet/in.h> | 
|  | #include <netinet/in_var.h> | 
|  | #include <arpa/inet.h> | 
|  | #include <netdb.h> | 
|  | #include <libc.h> | 
|  | #include <ip.h> | 
|  |  | 
|  | static void | 
|  | sockaddr2ip(uchar *ip, struct sockaddr *sa) | 
|  | { | 
|  | struct sockaddr_in *sin; | 
|  |  | 
|  | sin = (struct sockaddr_in*)sa; | 
|  | memmove(ip, v4prefix, IPaddrlen); | 
|  | memmove(ip+IPv4off, &sin->sin_addr, 4); | 
|  | } | 
|  |  | 
|  | Ipifc* | 
|  | readipifc(char *net, Ipifc *ifc, int index) | 
|  | { | 
|  | char *p, *ep, *q, *bp; | 
|  | int i, mib[6]; | 
|  | size_t n; | 
|  | Ipifc *list, **last; | 
|  | Iplifc *lifc, **lastlifc; | 
|  | struct if_msghdr *mh, *nmh; | 
|  | struct ifa_msghdr *ah; | 
|  | struct sockaddr *sa; | 
|  | struct sockaddr_dl *sdl; | 
|  | uchar ip[IPaddrlen]; | 
|  |  | 
|  | USED(net); | 
|  |  | 
|  | free(ifc); | 
|  | ifc = nil; | 
|  | list = nil; | 
|  | last = &list; | 
|  |  | 
|  | /* | 
|  | * Does not handle IPv6 yet. | 
|  | */ | 
|  |  | 
|  | mib[0] = CTL_NET; | 
|  | mib[1] = PF_ROUTE; | 
|  | mib[2] = 0; | 
|  | mib[3] = 0; | 
|  | mib[4] = NET_RT_IFLIST; | 
|  | mib[5] = 0; | 
|  |  | 
|  | n = 0; | 
|  | if(sysctl(mib, 6, nil, &n, nil, 0) < 0) | 
|  | return nil; | 
|  | bp = mallocz(n, 1); | 
|  | if(bp == nil) | 
|  | return nil; | 
|  | if(sysctl(mib, 6, bp, &n, nil, 0) < 0){ | 
|  | free(bp); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | p = bp; | 
|  | ep = p+n; | 
|  | while(p < ep){ | 
|  | mh = (struct if_msghdr*)p; | 
|  | p += mh->ifm_msglen; | 
|  | if(mh->ifm_type != RTM_IFINFO) | 
|  | continue; | 
|  | ifc = mallocz(sizeof *ifc, 1); | 
|  | if(ifc == nil) | 
|  | break; | 
|  | *last = ifc; | 
|  | last = &ifc->next; | 
|  | sdl = (struct sockaddr_dl*)(mh+1); | 
|  | n = sdl->sdl_nlen; | 
|  | if(n >= sizeof ifc->dev) | 
|  | n = sizeof ifc->dev - 1; | 
|  | memmove(ifc->dev, sdl->sdl_data, n); | 
|  | ifc->dev[n] = 0; | 
|  | ifc->rp.linkmtu = mh->ifm_data.ifi_mtu; | 
|  | lastlifc = &ifc->lifc; | 
|  |  | 
|  | if(sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == 6) | 
|  | memmove(ifc->ether, LLADDR(sdl), 6); | 
|  |  | 
|  | while(p < ep){ | 
|  | ah = (struct ifa_msghdr*)p; | 
|  | nmh = (struct if_msghdr*)p; | 
|  | if(nmh->ifm_type != RTM_NEWADDR) | 
|  | break; | 
|  | p += nmh->ifm_msglen; | 
|  | lifc = nil; | 
|  | for(i=0, q=(char*)(ah+1); i<RTAX_MAX && q<p; i++){ | 
|  | if(!(ah->ifam_addrs & (1<<i))) | 
|  | continue; | 
|  | sa = (struct sockaddr*)q; | 
|  | q += (sa->sa_len+sizeof(long)-1) & ~(sizeof(long)-1); | 
|  | if(sa->sa_family != AF_INET) | 
|  | continue; | 
|  | if(lifc == nil){ | 
|  | lifc = mallocz(sizeof *lifc, 1); | 
|  | if(lifc == nil) | 
|  | continue; | 
|  | *lastlifc = lifc; | 
|  | lastlifc = &lifc->next; | 
|  | } | 
|  | sockaddr2ip(ip, sa); | 
|  | switch(i){ | 
|  | case RTAX_IFA: | 
|  | ipmove(lifc->ip, ip); | 
|  | break; | 
|  | case RTAX_NETMASK: | 
|  | memset(ip, 0xFF, IPv4off); | 
|  | ipmove(lifc->mask, ip); | 
|  | break; | 
|  | case RTAX_BRD: | 
|  | if(mh->ifm_flags & IFF_POINTOPOINT) | 
|  | /* ipmove(lifc->remote, ip) */ ; | 
|  | if(mh->ifm_flags & IFF_BROADCAST) | 
|  | /* ipmove(lifc->bcast, ip) */ ; | 
|  | break; | 
|  | case RTAX_GATEWAY: | 
|  | break; | 
|  | case RTAX_DST: | 
|  | break; | 
|  | } | 
|  | } | 
|  | if(lifc) | 
|  | maskip(lifc->ip, lifc->mask, lifc->net); | 
|  | } | 
|  | } | 
|  | free(bp); | 
|  | return list; | 
|  | } |