#include "global.h"
/*
* io_get1stiface() - Get first interface of host
*
* @szIface = interface string buffer
* @iflen = size of interface buffer
* return: -1 error or 0 ok
*/
int
io_get1stiface(char *szIface, int iflen)
{
struct ifaddrs *ifa;
if (!szIface || !iflen)
return -1;
getifaddrs(&ifa);
strlcpy(szIface, ifa->ifa_name, iflen);
freeifaddrs(ifa);
return 0;
}
/*
* io_etherClose() - Close BPF interface
*
* @eth = bpf handle
* @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
* return: none
*/
void
io_etherClose(int eth, void **zcbuf)
{
#ifdef __FreeBSD__
struct bpf_zbuf *zbuf = NULL;
#endif
if (eth > STDERR_FILENO)
close(eth);
if (zcbuf && *zcbuf) {
#ifdef __FreeBSD__
zbuf = *zcbuf;
munmap(zbuf->bz_bufb, zbuf->bz_buflen);
munmap(zbuf->bz_bufa, zbuf->bz_buflen);
e_free(*zcbuf);
*zcbuf = NULL;
#endif
}
}
#ifdef __FreeBSD__
static inline struct bpf_zbuf *
allocZCbuf(u_int len)
{
struct bpf_zbuf *zbuf = NULL;
zbuf = e_malloc(sizeof(struct bpf_zbuf));
if (!zbuf) {
io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
return NULL;
} else
memset(zbuf, 0, sizeof(struct bpf_zbuf));
zbuf->bz_buflen = roundup(len, getpagesize());
zbuf->bz_bufa = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
if (zbuf->bz_bufa == MAP_FAILED) {
LOGERR;
e_free(zbuf);
return NULL;
} else
memset(zbuf->bz_bufa, 0, zbuf->bz_buflen);
zbuf->bz_bufb = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
if (zbuf->bz_bufb == MAP_FAILED) {
LOGERR;
munmap(zbuf->bz_bufa, zbuf->bz_buflen);
e_free(zbuf);
return NULL;
} else
memset(zbuf->bz_bufb, 0, zbuf->bz_buflen);
return zbuf;
}
#endif
/*
* io_etherOpen() - Open BPF interface to device
*
* @csIface = interface name
* @flags = open flags
* @whdr = with complete headers
* @buflen = buffer length
* @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
* return: -1 error or >-1 bpf handle
*/
int
io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
{
int n = 1, eth = -1;
register int i;
char szStr[STRSIZ];
struct ifreq ifr;
for (i = 0; i < BPF_DEV_MAX; i++) {
memset(szStr, 0, sizeof szStr);
snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
eth = open(szStr, flags);
if (eth > STDERR_FILENO)
break;
}
if (eth < 3) {
LOGERR;
return -1;
}
if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
LOGERR;
close(eth);
return -1;
}
if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
LOGERR;
close(eth);
return -1;
}
if (buflen && *buflen) {
if (!zcbuf) {
if (ioctl(eth, BIOCSBLEN, buflen) == -1) {
LOGERR;
close(eth);
return -1;
}
} else {
#ifdef __FreeBSD__
n = BPF_BUFMODE_ZBUF;
if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
LOGERR;
close(eth);
return -1;
}
if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
LOGERR;
close(eth);
return -1;
} else
*buflen = MIN(n, *buflen);
if (!(*zcbuf = allocZCbuf(*buflen))) {
close(eth);
return -1;
}
if (ioctl(eth, BIOCSETZBUF, (struct bpf_zbuf*) *zcbuf) == -1) {
LOGERR;
io_etherClose(eth, zcbuf);
return -1;
}
#endif
}
}
if (csIface)
strlcpy(szStr, csIface, sizeof szStr);
else if (io_get1stiface(szStr, sizeof szStr) == -1) {
io_etherClose(eth, zcbuf);
return -1;
}
strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
LOGERR;
io_etherClose(eth, zcbuf);
return -1;
}
return eth;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>