851 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			851 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #if 1
 | |
| 
 | |
| #define _GNU_SOURCE
 | |
| #include "hawk-prv.h"
 | |
| #include "skad-prv.h"
 | |
| #include <hawk-sio.h>
 | |
| 
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #	include <winsock2.h>
 | |
| #	include <ws2tcpip.h>
 | |
| /*#	include <iphlpapi.h> */
 | |
| #elif defined(__OS2__)
 | |
| #	if defined(TCPV40HDRS)
 | |
| #		define BSD_SELECT
 | |
| #	endif
 | |
| #	include <types.h>
 | |
| #	include <sys/socket.h>
 | |
| #	include <netinet/in.h>
 | |
| #	include <sys/ioctl.h>
 | |
| #	include <nerrno.h>
 | |
| #	if defined(TCPV40HDRS)
 | |
| #		define USE_SELECT
 | |
| #		include <sys/select.h>
 | |
| #	else
 | |
| #		include <unistd.h>
 | |
| #	endif
 | |
| #elif defined(__DOS__)
 | |
| 	/* TODO: */
 | |
| #else
 | |
| #	if !defined(_GNU_SOURCE)
 | |
| #		define _GNU_SOURCE
 | |
| #	endif
 | |
| #	include "syscall.h"
 | |
| #	include <sys/socket.h>
 | |
| #	include <netinet/in.h>
 | |
| #	if defined(HAVE_SYS_IOCTL_H)
 | |
| #		include <sys/ioctl.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_NET_IF_H)
 | |
| #		include <net/if.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_NET_IF_DL_H)
 | |
| #		include <net/if_dl.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_NET_ROUTE_H)
 | |
| #		include <net/route.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_SYS_SOCKIO_H)
 | |
| #		include <sys/sockio.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_IFADDRS_H)
 | |
| #		include <ifaddrs.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_SYS_SYSCTL_H)
 | |
| #		include <sys/sysctl.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_SYS_STROPTS_H)
 | |
| #		include <sys/stropts.h> /* stream options */
 | |
| #	endif
 | |
| #	if defined(HAVE_SYS_MACSTAT_H)
 | |
| #		include <sys/macstat.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_LINUX_ETHTOOL_H)
 | |
| #		include <linux/ethtool.h>
 | |
| #	endif
 | |
| #	if defined(HAVE_LINUX_SOCKIOS_H)
 | |
| #		include <linux/sockios.h>
 | |
| #	endif
 | |
| #endif
 | |
| 
 | |
| #if defined(AF_INET6)
 | |
| static int prefix_to_in6 (int prefix, struct in6_addr* in6)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	if (prefix < 0 || prefix > HAWK_SIZEOF(*in6) * 8) return -1;
 | |
| 
 | |
| 	HAWK_MEMSET(in6, 0, HAWK_SIZEOF(*in6));
 | |
| 	for (i = 0; ; i++)
 | |
| 	{
 | |
| 		 if (prefix > 8)
 | |
| 		 {
 | |
| 			in6->s6_addr[i] = 0xFF;
 | |
| 			prefix -= 8;
 | |
| 		 }
 | |
| 		 else
 | |
| 		 {
 | |
| 			in6->s6_addr[i] = 0xFF << (8 - prefix);
 | |
| 			break;
 | |
| 		 }
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static HAWK_INLINE void copy_to_skad (struct sockaddr* sa, hawk_oow_t sa_size, hawk_skad_t* skad)
 | |
| {
 | |
| 	hawk_oow_t len;
 | |
| 	len = (sa_size <= HAWK_SIZEOF(*skad))? sa_size: HAWK_SIZEOF(*skad);
 | |
| 	HAWK_MEMCPY(skad, sa, len);
 | |
| }
 | |
| /*
 | |
| 
 | |
| #if defined(HAVE_NET_IF_DL_H)
 | |
| #	include <net/if_dl.h>
 | |
| #endif
 | |
|  #ifndef SIOCGLIFHWADDR
 | |
| #define SIOCGLIFHWADDR  _IOWR('i', 192, struct lifreq)
 | |
|  #endif
 | |
| 
 | |
|     struct lifreq lif;
 | |
| 
 | |
|     memset(&lif, 0, sizeof(lif));
 | |
|     strlcpy(lif.lifr_name, ifname, sizeof(lif.lifr_name));
 | |
| 
 | |
|     if (ioctl(sock, SIOCGLIFHWADDR, &lif) != -1) {
 | |
|         struct sockaddr_dl *sp;
 | |
|         sp = (struct sockaddr_dl *)&lif.lifr_addr;
 | |
|         memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
 | |
|         return sp->sdl_alen;
 | |
|     }
 | |
| */
 | |
| 
 | |
| 
 | |
| #if 0
 | |
| #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && \
 | |
|     defined(HAVE_STRUCT_LIFCONF) && defined(HAVE_STRUCT_LIFREQ)
 | |
| static int get_nwifs (hawk_gem_t* gem, int s, int f, hawk_xptl_t* nwifs)
 | |
| {
 | |
| 	struct lifnum ifn;
 | |
| 	struct lifconf ifc;
 | |
| 	hawk_xptl_t b;
 | |
| 	hawk_oow_t ifcount;
 | |
| 
 | |
| 	ifcount = 0;
 | |
| 
 | |
| 	b.ptr = HAWK_NULL;
 | |
| 	b.len = 0;
 | |
| 
 | |
| 	do
 | |
| 	{
 | |
| 		ifn.lifn_family = f;
 | |
| 		ifn.lifn_flags  = 0;
 | |
| 		if (ioctl(s, SIOCGLIFNUM, &ifn) <= -1)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		if (b.ptr)
 | |
| 		{
 | |
| 			/* b.ptr won't be HAWK_NULL when retrying */
 | |
| 			if (ifn.lifn_count <= ifcount) break;
 | |
| 		}
 | |
| 
 | |
| 		/* +1 for extra space to leave empty
 | |
| 		 * if SIOCGLIFCONF returns the same number of
 | |
| 		 * intefaces as SIOCLIFNUM */
 | |
| 		b.len = (ifn.lifn_count + 1) * HAWK_SIZEOF(struct lifreq);
 | |
| 		b.ptr = hawk_gem_allocmem(gem, b.len);
 | |
| 		if (b.ptr == HAWK_NULL)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		ifc.lifc_family = f;
 | |
| 		ifc.lifc_flags = 0;
 | |
| 		ifc.lifc_len = b.len;
 | |
| 		ifc.lifc_buf = b.ptr;
 | |
| 
 | |
| 		if (ioctl(s, SIOCGLIFCONF, &ifc) <= -1)
 | |
| 		{
 | |
| 			hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 			goto oops;
 | |
| 		}
 | |
| 
 | |
| 		ifcount = ifc.lifc_len / HAWK_SIZEOF(struct lifreq);
 | |
| 	}
 | |
| 	while (ifcount > ifn.lifn_count);
 | |
| 	/* the while condition above is for checking if
 | |
| 	 * the buffer got full. when it's full, there is a chance
 | |
| 	 * that there are more interfaces. */
 | |
| 
 | |
| 	nwifs->ptr = b.ptr;
 | |
| 	nwifs->len = ifcount;
 | |
| 	return 0;
 | |
| 
 | |
| oops:
 | |
| 	if (b.ptr) hawk_gem_freemem (gem, b.ptr);
 | |
| 	return -1;
 | |
| }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
| static void free_nwifcfg (hawk_gem_t* gem, hawk_ifcfg_node_t* cfg)
 | |
| {
 | |
| 	hawk_ifcfg_node_t* cur;
 | |
| 
 | |
| 	while (cfg)
 | |
| 	{
 | |
| 		cur = cfg;
 | |
| 		cfg = cur->next;
 | |
| 		if (cur->name) hawk_gem_freemem (gem, cur->name);
 | |
| 		hawk_gem_freemem (gem, cur);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_gem_getifcfg (hawk_gem_t* gem, hawk_ifcfg_t* cfg)
 | |
| {
 | |
| #if defined(SIOCGLIFCONF)
 | |
| 	struct lifreq* ifr, ifrbuf;
 | |
| 	hawk_oow_t i;
 | |
| 	int s, f;
 | |
| 	int s4 = -1;
 | |
| 	int s6 = -1;
 | |
| 	hawk_xptl_t nwifs = { HAWK_NULL, 0 };
 | |
| 	hawk_ifcfg_node_t* head = HAWK_NULL;
 | |
| 	hawk_ifcfg_node_t* tmp;
 | |
| 
 | |
| 	HAWK_ASSERT (cfg->mmgr != HAWK_NULL);
 | |
| 
 | |
| #if defined(AF_INET) || defined(AF_INET6)
 | |
| 	#if defined(AF_INET)
 | |
| 	s4 = socket(AF_INET, SOCK_DGRAM, 0);
 | |
| 	if (s4 <= -1) goto sys_oops;
 | |
| 	#endif
 | |
| 
 | |
| 	#if defined(AF_INET6)
 | |
| 	s6 = socket (AF_INET6, SOCK_DGRAM, 0);
 | |
| 	if (s6 <= -1) goto oops;
 | |
| 	#endif
 | |
| #else
 | |
| 	/* no implementation */
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	goto oops;
 | |
| #endif
 | |
| 
 | |
| 	if (get_nwifs(cfg->mmgr, s4, AF_UNSPEC, &nwifs) <= -1) goto oops;
 | |
| 
 | |
| 	ifr = nwifs.ptr;
 | |
| 	for (i = 0; i < nwifs.len; i++, ifr++)
 | |
| 	{
 | |
| 		f = ifr->lifr_addr.ss_family;
 | |
| 
 | |
| 		if (f == AF_INET) s = s4;
 | |
| 		else if (f == AF_INET6) s = s6;
 | |
| 		else continue;
 | |
| 
 | |
| 		tmp = hawk_gem_allocmem(gem, HAWK_SIZEOF(*tmp));
 | |
| 		if (tmp == HAWK_NULL) goto oops;
 | |
| 
 | |
| 		HAWK_MEMSET(tmp, 0, HAWK_SIZEOF(*tmp));
 | |
| 		tmp->next = head;
 | |
| 		head = tmp;
 | |
| 
 | |
| #if defined(HAWK_OOCH_IS_BCH)
 | |
| 		head->name = hawk_gem_dupbcstr(gem, ifr->lifr_name, HAWK_NULL);
 | |
| #else
 | |
| 		head->name = hawk_gem_dupbtoucstr(gem, ifr->lifr_name, HAWK_NULL, 0);
 | |
| #endif
 | |
| 		if (head->name == HAWK_NULL) goto oops;
 | |
| 
 | |
| 		copy_to_skad((struct sockaddr*)&ifr->lifr_addr, HAWK_SIZEOF(ifr->lifr_addr), &head->addr);
 | |
| 
 | |
| 		hawk_copy_bcstr (ifrbuf.lifr_name, HAWK_COUNTOF(ifrbuf.lifr_name), ifr->lifr_name);
 | |
| 		if (ioctl(s, SIOCGLIFFLAGS, &ifrbuf) <= -1) goto sys_oops;
 | |
| 		if (ifrbuf.lifr_flags & IFF_UP) head->flags |= HAWK_IFCFG_UP;
 | |
| 		if (ifrbuf.lifr_flags & IFF_BROADCAST)
 | |
| 		{
 | |
| 			if (ioctl(s, SIOCGLIFBRDADDR, &ifrbuf) <= -1) goto sys_oops;
 | |
| 			copy_to_skad((struct sockaddr*)&ifrbuf.lifr_addr, HAWK_SIZEOF(ifrbuf.lifr_addr), &head->bcast);
 | |
| 			head->flags |= HAWK_IFCFG_BCAST;
 | |
| 		}
 | |
| 		if (ifrbuf.lifr_flags & IFF_POINTOPOINT)
 | |
| 		{
 | |
| 			if (ioctl(s, SIOCGLIFDSTADDR, &ifrbuf) <= -1) goto sys_oops;
 | |
| 			copy_to_skad((struct sockaddr*)&ifrbuf.lifr_addr, HAWK_SIZEOF(ifrbuf.lifr_addr), &head->ptop);
 | |
| 			head->flags |= HAWK_IFCFG_PTOP;
 | |
| 		}
 | |
| 
 | |
| 		if (ioctl(s, SIOCGLIFINDEX, &ifrbuf) <= -1) goto sys_oops;
 | |
| 		head->index = ifrbuf.lifr_index;
 | |
| 
 | |
| 		if (ioctl(s, SIOCGLIFNETMASK, &ifrbuf) <= -1) goto sys_oops;
 | |
| 		copy_to_skad((struct sockaddr*)&ifrbuf.lifr_addr, HAWK_SIZEOF(ifrbuf.lifr_addr), &head->mask);
 | |
| 	}
 | |
| 
 | |
| 	hawk_gem_freemem (gem, nwifs.ptr);
 | |
| 	close (s6);
 | |
| 	close (s4);
 | |
| 
 | |
| 	cfg->list = head;
 | |
| 	return 0;
 | |
| 
 | |
| sys_oops:
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| oops:
 | |
| 	if (head) free_nwifcfg (cfg->mmgr, head);
 | |
| 	if (nwifs.ptr) hawk_gem_freemem (gem, nwifs.ptr);
 | |
| 	if (s6 >= 0) close (s6);
 | |
| 	if (s4 >= 0) close (s4);
 | |
| 	return -1;
 | |
| #else
 | |
| 
 | |
| 	/* TODO  */
 | |
| 	return HAWK_NULL;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void hawk_freenwifcfg (hawk_ifcfg_t* cfg)
 | |
| {
 | |
| 	free_nwifcfg (cfg->mmgr, cfg->list);
 | |
| 	cfg->list = HAWK_NULL;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #if defined(__linux)
 | |
| static void read_proc_net_if_inet6 (hawk_gem_t* gem, hawk_ifcfg_t* cfg, struct ifreq* ifr)
 | |
| {
 | |
| 	/*
 | |
|      *
 | |
| 	 * # cat /proc/net/if_inet6
 | |
| 	 * 00000000000000000000000000000001 01 80 10 80 lo
 | |
| 	 * +------------------------------+ ++ ++ ++ ++ ++
 | |
| 	 * |                                |  |  |  |  |
 | |
| 	 * 1                                2  3  4  5  6
 | |
| 	 *
 | |
| 	 * 1. IPv6 address displayed in 32 hexadecimal chars without colons as separator
 | |
| 	 * 2. Netlink device number (interface index) in hexadecimal (see “ip addr” , too)
 | |
| 	 * 3. Prefix length in hexadecimal
 | |
| 	 * 4. Scope value (see kernel source “ include/net/ipv6.h” and “net/ipv6/addrconf.c” for more)
 | |
| 	 * 5. Interface flags (see “include/linux/rtnetlink.h” and “net/ipv6/addrconf.c” for more)
 | |
| 	 * 6. Device name
 | |
| 	 */
 | |
| 
 | |
| 	hawk_sio_t* sio;
 | |
| 	hawk_bch_t line[128];
 | |
| 	hawk_bch_t* ptr, * ptr2;
 | |
| 	hawk_ooi_t len;
 | |
| 	hawk_bcs_t tok[6];
 | |
| 	int count, index;
 | |
| 
 | |
| 	/* TODO */
 | |
| 
 | |
| 	sio = hawk_sio_open(gem, 0, HAWK_T("/proc/net/if_inet6"), HAWK_SIO_IGNOREECERR | HAWK_SIO_READ);
 | |
| 	if (sio)
 | |
| 	{
 | |
| 
 | |
| 		while (1)
 | |
| 		{
 | |
| 			len = hawk_sio_getbcstr(sio, line, HAWK_COUNTOF(line));
 | |
| 			if (len <= 0) break;
 | |
| 
 | |
| 			count = 0;
 | |
| 			ptr = line;
 | |
| 
 | |
| 			while (ptr && count < 6)
 | |
| 			{
 | |
| 				ptr2 = hawk_tokenize_bchars(ptr, len, " \t", 2, &tok[count], 0);
 | |
| 
 | |
| 				len -= ptr2 - ptr;
 | |
| 				ptr = ptr2;
 | |
| 				count++;
 | |
| 			}
 | |
| 
 | |
| 			if (count >= 6)
 | |
| 			{
 | |
| 				index = hawk_bchars_to_int(tok[1].ptr, tok[1].len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(1, 1, 16), HAWK_NULL, HAWK_NULL);
 | |
| 				if (index == cfg->index)
 | |
| 				{
 | |
| 					int ti;
 | |
| 					hawk_skad_alt_t* skad;
 | |
| 
 | |
| 					skad = (hawk_skad_alt_t*)&cfg->addr;
 | |
| 					if (hawk_bchars_to_bin(tok[0].ptr, tok[0].len, (hawk_uint8_t*)&skad->in6.sin6_addr, HAWK_SIZEOF(skad->in6.sin6_addr)) <= -1) break;
 | |
| 					/* tok[3] is the scope type, not the actual scope.
 | |
| 					 * i leave this code for reference only.
 | |
| 					skad->in6.sin6_scope_id = hawk_bchars_to_int(tok[3].ptr, tok[3].len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(1, 1, 16), HAWK_NULL, HAWK_NULL); */
 | |
| 					skad->in6.sin6_family = HAWK_AF_INET6;
 | |
| 
 | |
| 					skad = (hawk_skad_alt_t*)&cfg->mask;
 | |
| 					ti = hawk_bchars_to_int(tok[2].ptr, tok[0].len, HAWK_OOCHARS_TO_INT_MAKE_OPTION(1, 1, 16), HAWK_NULL, HAWK_NULL);
 | |
| 					prefix_to_in6 (ti, &skad->in6.sin6_addr);
 | |
| 					skad->in6.sin6_family = HAWK_AF_INET6;
 | |
| 					goto done;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	done:
 | |
| 		hawk_sio_close (sio);
 | |
| 	}
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static int get_ifcfg (hawk_gem_t* gem, int s, hawk_ifcfg_t* cfg, struct ifreq* ifr)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| 
 | |
| #elif defined(__OS2__)
 | |
| 
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| 
 | |
| #elif defined(__DOS__)
 | |
| 
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| 
 | |
| 
 | |
| #elif defined(SIOCGLIFADDR) && defined(SIOCGLIFINDEX) && defined(HAVE_STRUCT_LIFCONF) && defined(HAVE_STRUCT_LIFREQ)
 | |
| 	/* opensolaris */
 | |
| 	struct lifreq lifrbuf;
 | |
| 	hawk_oow_t ml, wl;
 | |
| 
 | |
| 	HAWK_MEMSET(&lifrbuf, 0, HAWK_SIZEOF(lifrbuf));
 | |
| 
 | |
| 	hawk_copy_bcstr (lifrbuf.lifr_name, HAWK_SIZEOF(lifrbuf.lifr_name), ifr->ifr_name);
 | |
| 
 | |
| 	if (ioctl(s, SIOCGLIFINDEX, &lifrbuf) <= -1) return -1;
 | |
| 	cfg->index = lifrbuf.lifr_index;
 | |
| 
 | |
| 	if (ioctl(s, SIOCGLIFFLAGS, &lifrbuf) <= -1) return -1;
 | |
| 	cfg->flags = 0;
 | |
| 	if (lifrbuf.lifr_flags & IFF_UP) cfg->flags |= HAWK_IFCFG_UP;
 | |
| 	if (lifrbuf.lifr_flags & IFF_RUNNING) cfg->flags |= HAWK_IFCFG_RUNNING;
 | |
| 	if (lifrbuf.lifr_flags & IFF_BROADCAST) cfg->flags |= HAWK_IFCFG_BCAST;
 | |
| 	if (lifrbuf.lifr_flags & IFF_POINTOPOINT) cfg->flags |= HAWK_IFCFG_PTOP;
 | |
| 
 | |
| 	if (ioctl(s, SIOCGLIFMTU, &lifrbuf) <= -1) return -1;
 | |
| 	cfg->mtu = lifrbuf.lifr_mtu;
 | |
| 
 | |
| 	hawk_clear_skad(&cfg->addr);
 | |
| 	hawk_clear_skad(&cfg->mask);
 | |
| 	hawk_clear_skad(&cfg->bcast);
 | |
| 	hawk_clear_skad(&cfg->ptop);
 | |
| 	HAWK_MEMSET(cfg->ethw, 0, HAWK_SIZEOF(cfg->ethw));
 | |
| 
 | |
| 	if (ioctl(s, SIOCGLIFADDR, &lifrbuf) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&lifrbuf.lifr_addr, HAWK_SIZEOF(lifrbuf.lifr_addr), &cfg->addr);
 | |
| 
 | |
| 	if (ioctl(s, SIOCGLIFNETMASK, &lifrbuf) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&lifrbuf.lifr_addr, HAWK_SIZEOF(lifrbuf.lifr_addr), &cfg->mask);
 | |
| 
 | |
| 	if ((cfg->flags & HAWK_IFCFG_BCAST) && ioctl(s, SIOCGLIFBRDADDR, &lifrbuf) >= 0)
 | |
| 	{
 | |
| 		copy_to_skad((struct sockaddr*)&lifrbuf.lifr_broadaddr, HAWK_SIZEOF(lifrbuf.lifr_broadaddr), &cfg->bcast);
 | |
| 	}
 | |
| 	if ((cfg->flags & HAWK_IFCFG_PTOP) && ioctl(s, SIOCGLIFDSTADDR, &lifrbuf) >= 0)
 | |
| 	{
 | |
| 		copy_to_skad((struct sockaddr*)&lifrbuf.lifr_dstaddr, HAWK_SIZEOF(lifrbuf.lifr_dstAddr), &cfg->ptop);
 | |
| 	}
 | |
| 
 | |
| 	#if defined(SIOCGENADDR)
 | |
| 	{
 | |
| 		if (ioctl(s, SIOCGENADDR, ifr) >= 0 && HAWK_SIZEOF(ifr->ifr_enaddr) >= HAWK_SIZEOF(cfg->ethw))
 | |
| 		{
 | |
| 			HAWK_MEMCPY(cfg->ethw, ifr->ifr_enaddr, HAWK_SIZEOF(cfg->ethw));
 | |
| 		}
 | |
| 		/* TODO: try DLPI if SIOCGENADDR fails... */
 | |
| 	}
 | |
| 	#endif
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| #elif defined(SIOCGLIFADDR) && defined(HAVE_STRUCT_IF_LADDRREQ) && !defined(SIOCGLIFINDEX)
 | |
| 	/* freebsd */
 | |
| 	hawk_oow_t ml, wl;
 | |
| 
 | |
| 	#if defined(SIOCGIFINDEX)
 | |
| 	if (ioctl(s, SIOCGIFINDEX, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	#if defined(HAVE_STRUCT_IFREQ_IFR_IFINDEX)
 | |
| 	cfg->index = ifr->ifr_ifindex;
 | |
| 	#else
 | |
| 	cfg->index = ifr->ifr_index;
 | |
| 	#endif
 | |
| 	#else
 | |
| 	cfg->index = 0;
 | |
| 	#endif
 | |
| 
 | |
| 	if (ioctl(s, SIOCGIFFLAGS, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	cfg->flags = 0;
 | |
| 	if (ifr->ifr_flags & IFF_UP) cfg->flags |= HAWK_IFCFG_UP;
 | |
| 	if (ifr->ifr_flags & IFF_RUNNING) cfg->flags |= HAWK_IFCFG_RUNNING;
 | |
| 	if (ifr->ifr_flags & IFF_BROADCAST) cfg->flags |= HAWK_IFCFG_BCAST;
 | |
| 	if (ifr->ifr_flags & IFF_POINTOPOINT) cfg->flags |= HAWK_IFCFG_PTOP;
 | |
| 
 | |
| 	if (ioctl(s, SIOCGIFMTU, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	#if defined(HAVE_STRUCT_IFREQ_IFR_MTU)
 | |
| 	cfg->mtu = ifr->ifr_mtu;
 | |
| 	#else
 | |
| 	/* well, this is a bit dirty. but since all these are unions,
 | |
| 	 * the name must not really matter. some OSes just omitts defining
 | |
| 	 * the MTU field */
 | |
| 	cfg->mtu = ifr->ifr_metric;
 | |
| 	#endif
 | |
| 
 | |
| 	hawk_clear_skad(&cfg->addr);
 | |
| 	hawk_clear_skad(&cfg->mask);
 | |
| 	hawk_clear_skad(&cfg->bcast);
 | |
| 	hawk_clear_skad(&cfg->ptop);
 | |
| 	HAWK_MEMSET(cfg->ethw, 0, HAWK_SIZEOF(cfg->ethw));
 | |
| 
 | |
| 	if (cfg->type == HAWK_IFCFG_IN6)
 | |
| 	{
 | |
| 		struct if_laddrreq iflrbuf;
 | |
| 		HAWK_MEMSET(&iflrbuf, 0, HAWK_SIZEOF(iflrbuf));
 | |
| 		hawk_copy_bcstr (iflrbuf.iflr_name, HAWK_SIZEOF(iflrbuf.iflr_name), ifr->ifr_name);
 | |
| 
 | |
| 		if (ioctl(s, SIOCGLIFADDR, &iflrbuf) >= 0)
 | |
| 		{
 | |
| 			hawk_skad_alt_t* skad;
 | |
| 			copy_to_skad((struct sockaddr*)&iflrbuf.addr, HAWK_SIZEOF(iflrbuf.addr), &cfg->addr);
 | |
| 
 | |
| 			skad = (hawk_skad_alt_t*)&cfg->mask;
 | |
| 			skad->in6.sin6_family = HAWK_AF_INET6;
 | |
| 			prefix_to_in6 (iflrbuf.prefixlen, &skad->in6.sin6_addr);
 | |
| 
 | |
| 			if (cfg->flags & HAWK_IFCFG_PTOP)
 | |
| 				copy_to_skad((struct sockaddr*)&iflrbuf.dstaddr, HAWK_SIZEOF(iflrbuf.dstaddr), &cfg->ptop);
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (ioctl(s, SIOCGIFADDR, ifr) >= 0)
 | |
| 			copy_to_skad((struct sockaddr*)&ifr->ifr_addr, HAWK_SIZEOF(ifr->ifr_addr), &cfg->addr);
 | |
| 
 | |
| 		if (ioctl(s, SIOCGIFNETMASK, ifr) >= 0)
 | |
| 			copy_to_skad((struct sockaddr*)&ifr->ifr_addr, HAWK_SIZEOF(ifr->ifr_addr), &cfg->mask);
 | |
| 
 | |
| 		if ((cfg->flags & HAWK_IFCFG_BCAST) && ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
 | |
| 		{
 | |
| 			copy_to_skad((struct sockaddr*)&ifr->ifr_broadaddr, HAWK_SIZEOF(ifr->ifr_boradaddr), &cfg->bcast);
 | |
| 		}
 | |
| 
 | |
| 		if ((cfg->flags & HAWK_IFCFG_PTOP) && ioctl(s, SIOCGIFDSTADDR, ifr) >= 0)
 | |
| 		{
 | |
| 			copy_to_skad((struct sockaddr*)&ifr->ifr_dstaddr, HAWK_SIZEOF(ifr->ifr_dstaddr), &cfg->ptop);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	#if defined(CTL_NET) && defined(AF_ROUTE) && defined(AF_LINK)
 | |
| 	{
 | |
| 		int mib[6];
 | |
| 		size_t len;
 | |
| 
 | |
| 		mib[0] = CTL_NET;
 | |
| 		mib[1] = AF_ROUTE;
 | |
| 		mib[2] = 0;
 | |
| 		mib[3] = AF_LINK;
 | |
| 		mib[4] = NET_RT_IFLIST;
 | |
| 		mib[5] = cfg->index;
 | |
| 		if (sysctl(mib, HAWK_COUNTOF(mib), HAWK_NULL, &len, HAWK_NULL, 0) >= 0)
 | |
| 		{
 | |
| 			hawk_uint8_t* buf;
 | |
| 
 | |
| 			buf = hawk_gem_allocmem(gem, len);
 | |
| 			if (buf)
 | |
| 			{
 | |
| 				if (sysctl(mib, HAWK_COUNTOF(mib), buf, &len, HAWK_NULL, 0) >= 0)
 | |
| 				{
 | |
| 					hawk_uint8_t* ptr, * end;
 | |
| 					struct if_msghdr* ifm;
 | |
| 					struct sockaddr_dl* sadl;
 | |
| 
 | |
| 					ptr = buf;
 | |
| 					end = buf + len;
 | |
| 					while (ptr < end)
 | |
| 					{
 | |
| 						ifm = (struct if_msghdr*)ptr;
 | |
| 						sadl = (struct sockaddr_dl*)(ifm + 1);
 | |
| 
 | |
| 						/* i don't really care if it's really ethernet
 | |
| 						 * so long as the data is long enough */
 | |
| 						if (sadl->sdl_alen >= HAWK_COUNTOF(cfg->ethw))
 | |
| 						{
 | |
| 							HAWK_MEMCPY(cfg->ethw, LLADDR(sadl), HAWK_SIZEOF(cfg->ethw));
 | |
| 							break;
 | |
| 						}
 | |
| 
 | |
| 						ptr += ifm->ifm_msglen;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				hawk_gem_freemem (gem, buf);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	#endif
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| #elif defined(SIOCGIFADDR)
 | |
| 
 | |
| 	#if defined(SIOCGIFINDEX)
 | |
| 	if (ioctl(s, SIOCGIFINDEX, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	#if defined(HAVE_STRUCT_IFREQ_IFR_IFINDEX) || defined(ifr_ifindex)
 | |
| 	cfg->index = ifr->ifr_ifindex;
 | |
| 	#else
 | |
| 	cfg->index = ifr->ifr_index;
 | |
| 	#endif
 | |
| 
 | |
| 	#else
 | |
| 	cfg->index = 0;
 | |
| 	#endif
 | |
| 
 | |
| 	if (ioctl(s, SIOCGIFFLAGS, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	cfg->flags = 0;
 | |
| 	if (ifr->ifr_flags & IFF_UP) cfg->flags |= HAWK_IFCFG_UP;
 | |
| 	if (ifr->ifr_flags & IFF_RUNNING) cfg->flags |= HAWK_IFCFG_RUNNING;
 | |
| 	if (ifr->ifr_flags & IFF_BROADCAST) cfg->flags |= HAWK_IFCFG_BCAST;
 | |
| 	if (ifr->ifr_flags & IFF_POINTOPOINT) cfg->flags |= HAWK_IFCFG_PTOP;
 | |
| 
 | |
| 	if (ioctl(s, SIOCGIFMTU, ifr) <= -1)
 | |
| 	{
 | |
| 		hawk_gem_seterrnum(gem, HAWK_NULL, hawk_syserr_to_errnum(errno));
 | |
| 		return -1;
 | |
| 	}
 | |
| 	#if defined(HAVE_STRUCT_IFREQ_IFR_MTU)
 | |
| 	cfg->mtu = ifr->ifr_mtu;
 | |
| 	#else
 | |
| 	/* well, this is a bit dirty. but since all these are unions,
 | |
| 	 * the name must not really matter. SCO just omits defining
 | |
| 	 * the MTU field, and uses ifr_metric instead */
 | |
| 	cfg->mtu = ifr->ifr_metric;
 | |
| 	#endif
 | |
| 
 | |
| 	hawk_clear_skad(&cfg->addr);
 | |
| 	hawk_clear_skad(&cfg->mask);
 | |
| 	hawk_clear_skad(&cfg->bcast);
 | |
| 	hawk_clear_skad(&cfg->ptop);
 | |
| 	HAWK_MEMSET(cfg->ethw, 0, HAWK_SIZEOF(cfg->ethw));
 | |
| 
 | |
| 	if (ioctl(s, SIOCGIFADDR, ifr) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&ifr->ifr_addr, HAWK_SIZEOF(ifr->ifr_addr), &cfg->addr);
 | |
| 	if (ioctl(s, SIOCGIFNETMASK, ifr) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&ifr->ifr_addr, HAWK_SIZEOF(ifr->ifr_addr), &cfg->mask);
 | |
| 
 | |
| 	#if defined(__linux)
 | |
| 	if (hawk_skad_get_family(&cfg->addr) == HAWK_AF_UNSPEC && hawk_skad_get_family(&cfg->mask) == HAWK_AF_UNSPEC && cfg->type == HAWK_IFCFG_IN6)
 | |
| 	{
 | |
| 		/* access /proc/net/if_inet6 */
 | |
| 		read_proc_net_if_inet6 (gem, cfg, ifr);
 | |
| 	}
 | |
| 	#endif
 | |
| 
 | |
| 	if ((cfg->flags & HAWK_IFCFG_BCAST) && ioctl(s, SIOCGIFBRDADDR, ifr) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&ifr->ifr_broadaddr, HAWK_SIZEOF(ifr->ifr_broadaddr), &cfg->bcast);
 | |
| 
 | |
| 	if ((cfg->flags & HAWK_IFCFG_PTOP) && ioctl(s, SIOCGIFDSTADDR, ifr) >= 0)
 | |
| 		copy_to_skad((struct sockaddr*)&ifr->ifr_dstaddr, HAWK_SIZEOF(ifr->ifr_dstaddr), &cfg->ptop);
 | |
| 
 | |
| 	#if defined(SIOCGIFHWADDR)
 | |
| 	if (ioctl(s, SIOCGIFHWADDR, ifr) >= 0)
 | |
| 	{
 | |
| 		HAWK_MEMCPY(cfg->ethw, ifr->ifr_hwaddr.sa_data, HAWK_SIZEOF(cfg->ethw));
 | |
| 	}
 | |
| 	#elif defined(MACIOC_GETADDR)
 | |
| 	{
 | |
| 		/* sco openserver
 | |
| 		 * use the streams interface to get the hardware address.
 | |
| 		 */
 | |
| 		int strfd;
 | |
| 		hawk_bch_t devname[HAWK_COUNTOF(ifr->ifr_name) + 5 + 1];
 | |
| 
 | |
| 		hawk_copy_bcstr_unlimited(devname, HAWK_MT("/dev/"));
 | |
| 		hawk_copy_bcstr_unlimited(&devname[5], ifr->ifr_name);
 | |
| 		if ((strfd = HAWK_OPEN(devname, O_RDONLY, 0)) >= 0)
 | |
| 		{
 | |
| 			hawk_uint8_t buf[HAWK_SIZEOF(cfg->ethw)];
 | |
| 			struct strioctl strioc;
 | |
| 
 | |
| 			strioc.ic_cmd = MACIOC_GETADDR;
 | |
| 			strioc.ic_timout = -1;
 | |
| 			strioc.ic_len = HAWK_SIZEOF (buf);
 | |
| 			strioc.ic_dp = buf;
 | |
| 			if (ioctl(strfd, I_STR, (char *) &strioc) >= 0)
 | |
| 				HAWK_MEMCPY(cfg->ethw, buf, HAWK_SIZEOF(cfg->ethw));
 | |
| 
 | |
| 			HAWK_CLOSE (strfd);
 | |
| 		}
 | |
| 	}
 | |
| 	#endif
 | |
| 
 | |
| 	return 0;
 | |
| #else
 | |
| 
 | |
| 	/* TODO  */
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static void get_moreinfo (int s, hawk_ifcfg_t* cfg, struct ifreq* ifr)
 | |
| {
 | |
| #if defined(ETHTOOL_GLINK)
 | |
| 	{
 | |
| 		/* get link status */
 | |
| 		struct ethtool_value ev;
 | |
| 		HAWK_MEMSET(&ev, 0, HAWK_SIZEOF(ev));
 | |
| 		ev.cmd= ETHTOOL_GLINK;
 | |
| 		ifr->ifr_data = (void*)&ev;
 | |
| 		if (ioctl(s, SIOCETHTOOL, ifr) >= 0) cfg->flags |= ev.data? HAWK_IFCFG_LINKUP: HAWK_IFCFG_LINKDOWN;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| #if defined(ETHTOOL_GSTATS)
 | |
| 	{
 | |
| 		/* get link statistics */
 | |
| 		struct ethtool_drvinfo drvinfo;
 | |
| 
 | |
| 		drvinfo.cmd = ETHTOOL_GDRVINFO;
 | |
| 		ifr->ifr_data = &drvinfo;
 | |
| 		if (ioctl(s, SIOCETHTOOL, ifr) >= 0)
 | |
| 		{
 | |
| 			struct ethtool_stats *stats;
 | |
| 			hawk_uint8_t buf[1000]; /* TODO: make this dynamic according to drvinfo.n_stats */
 | |
| 
 | |
| 			stats = buf;
 | |
| 			stats->cmd = ETHTOOL_GSTATS;
 | |
| 			stats->n_stats = drvinfo.n_stats * HAWK_SIZEOF(stats->data[0]);
 | |
| 			ifr->ifr_data = (caddr_t) stats;
 | |
| 			if (ioctl(s, SIOCETHTOOL, ifr) >= 0)
 | |
| 			{
 | |
| for (i = 0; i  < drvinfo.n_stats; i++)
 | |
| {
 | |
| 	hawk_printf (HAWK_T(">>> %llu \n"), stats->data[i]);
 | |
| }
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* TOOD: consider how to handle multiple IPv6 addresses on a single interfce.
 | |
|  *       consider how to get IPv4 addresses on an aliased interface? so mutliple ipv4 addresses */
 | |
| 
 | |
| int hawk_gem_getifcfg (hawk_gem_t* gem, hawk_ifcfg_t* cfg)
 | |
| {
 | |
| #if defined(_WIN32)
 | |
| 	/* TODO */
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| #elif defined(__OS2__)
 | |
| 	/* TODO */
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| #elif defined(__DOS__)
 | |
| 	/* TODO */
 | |
| 	hawk_gem_seterrnum(gem, HAWK_NULL, HAWK_ENOIMPL);
 | |
| 	return -1;
 | |
| #else
 | |
| 	int x = -1, s = -1;
 | |
| 	struct ifreq ifr;
 | |
| 	hawk_oow_t ml, wl;
 | |
| 
 | |
| 	if (cfg->type == HAWK_IFCFG_IN4)
 | |
| 	{
 | |
| 	#if defined(AF_INET)
 | |
| 		s = socket (AF_INET, SOCK_DGRAM, 0);
 | |
| 	#endif
 | |
| 	}
 | |
| 	else if (cfg->type == HAWK_IFCFG_IN6)
 | |
| 	{
 | |
| 	#if defined(AF_INET6)
 | |
| 		s = socket(AF_INET6, SOCK_DGRAM, 0);
 | |
| 	#endif
 | |
| 	}
 | |
| 	if (s <= -1) return -1;
 | |
| 
 | |
| 	if (cfg->name[0] == HAWK_T('\0')&& cfg->index >= 1)
 | |
| 	{
 | |
| /* TODO: support lookup by ifindex */
 | |
| 	}
 | |
| 
 | |
| 	HAWK_MEMSET(&ifr, 0, sizeof(ifr));
 | |
| 	#if defined(HAWK_OOCH_IS_BCH)
 | |
| 	hawk_copy_bcstr (ifr.ifr_name, HAWK_SIZEOF(ifr.ifr_name), cfg->name);
 | |
| 	#else
 | |
| 	ml = HAWK_COUNTOF(ifr.ifr_name);
 | |
| 	if (hawk_gem_convutobcstr(gem, cfg->name, &wl, ifr.ifr_name, &ml) <= -1)  goto oops;
 | |
| 	#endif
 | |
| 
 | |
| 	x = get_ifcfg(gem, s, cfg, &ifr);
 | |
| 
 | |
| 	if (x >= 0) get_moreinfo (s, cfg, &ifr);
 | |
| 
 | |
| oops:
 | |
| 	HAWK_CLOSE (s);
 | |
| 	return x;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #endif
 |