File:  [ELWIX - Embedded LightWeight unIX -] / libaitio / src / bpf.c
Revision 1.1.2.9: download - view: text, annotated - select for diffs - revision graph
Tue Jun 25 08:55:02 2013 UTC (11 years ago) by misho
Branches: io5_4
adds error handling

    1: #include "global.h"
    2: 
    3: 
    4: /*
    5:  * io_get1stiface() - Get first interface of host
    6:  *
    7:  * @szIface = interface string buffer
    8:  * @iflen = size of interface buffer
    9:  * return: -1 error or 0 ok
   10:  */
   11: int
   12: io_get1stiface(char *szIface, int iflen)
   13: {
   14: 	struct ifaddrs *ifa;
   15: 
   16: 	if (!szIface || !iflen)
   17: 		return -1;
   18: 
   19: 	getifaddrs(&ifa);
   20: 	strlcpy(szIface, ifa->ifa_name, iflen);
   21: 	freeifaddrs(ifa);
   22: 	return 0;
   23: }
   24: 
   25: /*
   26:  * io_etherClose() - Close BPF interface
   27:  *
   28:  * @eth = bpf handle
   29:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
   30:  * return: none
   31:  */
   32: void
   33: io_etherClose(int eth, void **zcbuf)
   34: {
   35: #ifdef __FreeBSD__
   36: 	struct bpf_zbuf *zbuf = NULL;
   37: #endif
   38: 
   39: 	if (eth > STDERR_FILENO)
   40: 		close(eth);
   41: 
   42: 	if (zcbuf && *zcbuf) {
   43: #ifdef __FreeBSD__
   44: 		zbuf = *zcbuf;
   45: 		munmap(zbuf->bz_bufb, zbuf->bz_buflen);
   46: 		munmap(zbuf->bz_bufa, zbuf->bz_buflen);
   47: 		e_free(*zcbuf);
   48: 		*zcbuf = NULL;
   49: #endif
   50: 	}
   51: }
   52: 
   53: #ifdef __FreeBSD__
   54: static inline struct bpf_zbuf *
   55: allocZCbuf(u_int len)
   56: {
   57: 	struct bpf_zbuf *zbuf = NULL;
   58: 
   59: 	zbuf = e_malloc(sizeof(struct bpf_zbuf));
   60: 	if (!zbuf) {
   61: 		io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
   62: 		return NULL;
   63: 	} else
   64: 		memset(zbuf, 0, sizeof(struct bpf_zbuf));
   65: 
   66: 	zbuf->bz_buflen = roundup(len, getpagesize());
   67: 	zbuf->bz_bufa = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
   68: 	if (zbuf->bz_bufa == MAP_FAILED) {
   69: 		LOGERR;
   70: 		e_free(zbuf);
   71: 		return NULL;
   72: 	} else
   73: 		memset(zbuf->bz_bufa, 0, zbuf->bz_buflen);
   74: 	zbuf->bz_bufb = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
   75: 	if (zbuf->bz_bufb == MAP_FAILED) {
   76: 		LOGERR;
   77: 		munmap(zbuf->bz_bufa, zbuf->bz_buflen);
   78: 		e_free(zbuf);
   79: 		return NULL;
   80: 	} else
   81: 		memset(zbuf->bz_bufb, 0, zbuf->bz_buflen);
   82: 
   83: 	return zbuf;
   84: }
   85: #endif
   86: 
   87: /*
   88:  * io_etherOpen() - Open BPF interface to device
   89:  *
   90:  * @csIface = interface name
   91:  * @flags = open flags
   92:  * @whdr = with complete headers
   93:  * @buflen = buffer length
   94:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
   95:  * return: -1 error or >-1 bpf handle
   96:  */
   97: int
   98: io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
   99: {
  100: 	int n = 1, eth = -1;
  101: 	register int i;
  102: 	char szStr[STRSIZ];
  103: 	struct ifreq ifr;
  104: 
  105: 	for (i = 0; i < BPF_DEV_MAX; i++) {
  106: 		memset(szStr, 0, sizeof szStr);
  107: 		snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
  108: 		eth = open(szStr, flags);
  109: 		if (eth > STDERR_FILENO)
  110: 			break;
  111: 	}
  112: 	if (eth < 3) {
  113: 		LOGERR;
  114: 		return -1;
  115: 	}
  116: 
  117: 	if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
  118: 		LOGERR;
  119: 		close(eth);
  120: 		return -1;
  121: 	}
  122: 	if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
  123: 		LOGERR;
  124: 		close(eth);
  125: 		return -1;
  126: 	}
  127: 	if (buflen && *buflen) {
  128: 		if (!zcbuf) {
  129: 			if (ioctl(eth, BIOCSBLEN, buflen) == -1) {
  130: 				LOGERR;
  131: 				close(eth);
  132: 				return -1;
  133: 			}
  134: 		} else {
  135: #ifdef __FreeBSD__
  136: 			n = BPF_BUFMODE_ZBUF;
  137: 			if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
  138: 				LOGERR;
  139: 				close(eth);
  140: 				return -1;
  141: 			}
  142: 			if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
  143: 				LOGERR;
  144: 				close(eth);
  145: 				return -1;
  146: 			} else
  147: 				*buflen = MIN(n, *buflen);
  148: 			if (!(*zcbuf = allocZCbuf(*buflen))) {
  149: 				close(eth);
  150: 				return -1;
  151: 			}
  152: 			if (ioctl(eth, BIOCSETZBUF, (struct bpf_zbuf*) *zcbuf) == -1) {
  153: 				LOGERR;
  154: 				io_etherClose(eth, zcbuf);
  155: 				return -1;
  156: 			}
  157: #endif
  158: 		}
  159: 	}
  160: 	if (csIface)
  161: 		strlcpy(szStr, csIface, sizeof szStr);
  162: 	else if (io_get1stiface(szStr, sizeof szStr) == -1) {
  163: 		io_etherClose(eth, zcbuf);
  164: 		return -1;
  165: 	}
  166: 	strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
  167: 	if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
  168: 		LOGERR;
  169: 		io_etherClose(eth, zcbuf);
  170: 		return -1;
  171: 	}
  172: 
  173: 	return eth;
  174: }
  175: 
  176: /*
  177:  * io_etherSend() - Send packet to bpf
  178:  *
  179:  * @eth = bpf handle
  180:  * @buf = buffer
  181:  * @buflen = buffer length
  182:  * return: -1 error or !=-1 written bytes
  183:  */
  184: ssize_t
  185: io_etherSend(int eth, const void *buf, size_t buflen)
  186: {
  187: 	ssize_t wlen = 0;
  188: 
  189: 	if (!buf || !buflen) {
  190: 		io_SetErr(EINVAL, "invalid arguments");
  191: 		return -1;
  192: 	}
  193: 
  194: 	wlen = write(eth, buf, buflen);
  195: 	if (wlen == -1)
  196: 		LOGERR;
  197: 	return wlen;
  198: }
  199: 
  200: #ifdef __FreeBSD__
  201: static inline void
  202: ackZCbuf(struct bpf_zbuf_header * __restrict bzh)
  203: {
  204: 	atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
  205: }
  206: 
  207: static inline int
  208: chkZCbuf(struct bpf_zbuf_header * __restrict bzh)
  209: {
  210: 	/* return true if userspace owns buffer, and false otherwise. */
  211: 	return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen));
  212: }
  213: 
  214: static inline ssize_t
  215: nextZCbuf(void ** __restrict zcache, struct bpf_zbuf * __restrict zbuf, 
  216: 		const void * __restrict buf)
  217: {
  218: 	ssize_t rlen = -1;
  219: 	struct bpf_zbuf_header *bzh;
  220: 
  221: 	if (!*zcache || *zcache == zbuf->bz_bufb) {
  222: 		bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
  223: 		if (chkZCbuf(bzh)) {
  224: 			rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
  225: 			*zcache = zbuf->bz_bufa;
  226: 			if (buf)
  227: 				buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
  228: 			ackZCbuf(bzh);
  229: 		} else
  230: 			io_SetErr(EAGAIN, "kernel owns the buffer");
  231: 	} else if (*zcache == zbuf->bz_bufa) {
  232: 		bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
  233: 		if (chkZCbuf(bzh)) {
  234: 			rlen = atomic_load_acq_int(&bzh->bzh_kernel_len);
  235: 			*zcache = zbuf->bz_bufb;
  236: 			if (buf)
  237: 				buf = ((caddr_t) *zcache) + sizeof(struct bpf_zbuf_header);
  238: 			ackZCbuf(bzh);
  239: 		} else
  240: 			io_SetErr(EAGAIN, "kernel owns the buffer");
  241: 	}
  242: 
  243: 	return rlen;
  244: }
  245: #endif
  246: 
  247: /*
  248:  * io_etherRecv() - Receive packet from bpf
  249:  *
  250:  * @eth = bpf handle
  251:  * @buf = buffer
  252:  * @buflen = buffer length
  253:  * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
  254:  * return: -1 error or !=-1 readed bytes
  255:  */
  256: ssize_t
  257: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
  258: {
  259: 	ssize_t rlen = 0;
  260: 	void **zcache = NULL;
  261: 
  262: 	if (!buf || !buflen) {
  263: 		io_SetErr(EINVAL, "invalid arguments");
  264: 		return -1;
  265: 	}
  266: 
  267: 	if (!zcbuf) {
  268: 		rlen = read(eth, buf, buflen);
  269: 		if (rlen == -1)
  270: 			LOGERR;
  271: 	} else {
  272: #ifdef __FreeBSD__
  273: 		rlen = nextZCbuf(zcache, (struct bpf_zbuf*) zcbuf, buf);
  274: #else
  275: 		io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
  276: #endif
  277: 	}
  278: 
  279: 	return rlen;
  280: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>