Annotation of libaitio/src/bpf.c, revision 1.2
1.2 ! misho 1: /*************************************************************************
! 2: * (C) 2013 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
! 3: * by Michael Pounov <misho@elwix.org>
! 4: *
! 5: * $Author: misho $
! 6: * $Id: bpf.c,v 1.1.2.21 2013/06/26 22:48:10 misho Exp $
! 7: *
! 8: **************************************************************************
! 9: The ELWIX and AITNET software is distributed under the following
! 10: terms:
! 11:
! 12: All of the documentation and software included in the ELWIX and AITNET
! 13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
! 14:
! 15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
! 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
! 17:
! 18: Redistribution and use in source and binary forms, with or without
! 19: modification, are permitted provided that the following conditions
! 20: are met:
! 21: 1. Redistributions of source code must retain the above copyright
! 22: notice, this list of conditions and the following disclaimer.
! 23: 2. Redistributions in binary form must reproduce the above copyright
! 24: notice, this list of conditions and the following disclaimer in the
! 25: documentation and/or other materials provided with the distribution.
! 26: 3. All advertising materials mentioning features or use of this software
! 27: must display the following acknowledgement:
! 28: This product includes software developed by Michael Pounov <misho@elwix.org>
! 29: ELWIX - Embedded LightWeight unIX and its contributors.
! 30: 4. Neither the name of AITNET nor the names of its contributors
! 31: may be used to endorse or promote products derived from this software
! 32: without specific prior written permission.
! 33:
! 34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
! 35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 44: SUCH DAMAGE.
! 45: */
! 46: #include "global.h"
! 47:
! 48:
! 49: /*
! 50: * io_get1stiface() - Get first interface of host
! 51: *
! 52: * @szIface = interface string buffer
! 53: * @iflen = size of interface buffer
! 54: * return: -1 error or 0 ok
! 55: */
! 56: int
! 57: io_get1stiface(char *szIface, int iflen)
! 58: {
! 59: struct ifaddrs *ifa;
! 60:
! 61: if (!szIface || !iflen)
! 62: return -1;
! 63:
! 64: getifaddrs(&ifa);
! 65: strlcpy(szIface, ifa->ifa_name, iflen);
! 66: freeifaddrs(ifa);
! 67: return 0;
! 68: }
! 69:
! 70: /*
! 71: * io_etherClose() - Close BPF interface
! 72: *
! 73: * @eth = bpf handle
! 74: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
! 75: * return: none
! 76: */
! 77: void
! 78: io_etherClose(int eth, void **zcbuf)
! 79: {
! 80: #ifdef __FreeBSD__
! 81: struct bpf_zbuf *zbuf = NULL;
! 82: #endif
! 83:
! 84: if (eth > STDERR_FILENO)
! 85: close(eth);
! 86:
! 87: if (zcbuf && *zcbuf) {
! 88: #ifdef __FreeBSD__
! 89: zbuf = *zcbuf;
! 90: munmap(zbuf->bz_bufb, zbuf->bz_buflen);
! 91: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
! 92: e_free(*zcbuf);
! 93: *zcbuf = NULL;
! 94: #endif
! 95: }
! 96: }
! 97:
! 98: #ifdef __FreeBSD__
! 99: static inline struct bpf_zbuf *
! 100: allocZCbuf(u_int len)
! 101: {
! 102: struct bpf_zbuf *zbuf = NULL;
! 103:
! 104: zbuf = e_malloc(sizeof(struct bpf_zbuf));
! 105: if (!zbuf) {
! 106: io_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
! 107: return NULL;
! 108: } else
! 109: memset(zbuf, 0, sizeof(struct bpf_zbuf));
! 110:
! 111: zbuf->bz_buflen = roundup(len, getpagesize());
! 112: zbuf->bz_bufa = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
! 113: if (zbuf->bz_bufa == MAP_FAILED) {
! 114: LOGERR;
! 115: e_free(zbuf);
! 116: return NULL;
! 117: } else
! 118: memset(zbuf->bz_bufa, 0, zbuf->bz_buflen);
! 119: zbuf->bz_bufb = mmap(NULL, zbuf->bz_buflen, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
! 120: if (zbuf->bz_bufb == MAP_FAILED) {
! 121: LOGERR;
! 122: munmap(zbuf->bz_bufa, zbuf->bz_buflen);
! 123: e_free(zbuf);
! 124: return NULL;
! 125: } else
! 126: memset(zbuf->bz_bufb, 0, zbuf->bz_buflen);
! 127:
! 128: return zbuf;
! 129: }
! 130: #endif
! 131:
! 132: /*
! 133: * io_etherOpen() - Open BPF interface to device
! 134: *
! 135: * @csIface = interface name
! 136: * @flags = open flags
! 137: * @whdr = with complete headers
! 138: * @buflen = buffer length
! 139: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
! 140: * return: -1 error or >-1 bpf handle
! 141: */
! 142: int
! 143: io_etherOpen(const char *csIface, int flags, int whdr, u_int *buflen, void **zcbuf)
! 144: {
! 145: int eth = -1;
! 146: register int i;
! 147: char szStr[STRSIZ];
! 148: struct ifreq ifr;
! 149: u_int n = 1;
! 150:
! 151: #ifndef __FreeBSD__
! 152: if (zcbuf) {
! 153: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
! 154: return -1;
! 155: }
! 156: #endif
! 157:
! 158: for (i = 0; i < BPF_DEV_MAX; i++) {
! 159: memset(szStr, 0, sizeof szStr);
! 160: snprintf(szStr, sizeof szStr, "/dev/bpf%d", i);
! 161: eth = open(szStr, flags);
! 162: if (eth > STDERR_FILENO)
! 163: break;
! 164: }
! 165: if (eth < 3) {
! 166: LOGERR;
! 167: return -1;
! 168: }
! 169:
! 170: if (!zcbuf) {
! 171: if (ioctl(eth, BIOCGBLEN, &n) == -1) {
! 172: LOGERR;
! 173: close(eth);
! 174: return -1;
! 175: } else
! 176: n = (buflen && *buflen) ? *buflen : n;
! 177: if (ioctl(eth, BIOCSBLEN, &n) == -1) {
! 178: LOGERR;
! 179: close(eth);
! 180: return -1;
! 181: }
! 182: if (buflen && *buflen)
! 183: *buflen = n;
! 184: } else {
! 185: #ifdef __FreeBSD__
! 186: n = BPF_BUFMODE_ZBUF;
! 187: if (ioctl(eth, BIOCSETBUFMODE, &n) == -1) {
! 188: LOGERR;
! 189: close(eth);
! 190: return -1;
! 191: }
! 192: if (ioctl(eth, BIOCGETZMAX, &n) == -1) {
! 193: LOGERR;
! 194: close(eth);
! 195: return -1;
! 196: } else
! 197: n = (buflen && *buflen) ? *buflen : n;
! 198: if (!(*zcbuf = allocZCbuf(n))) {
! 199: close(eth);
! 200: return -1;
! 201: }
! 202: if (ioctl(eth, BIOCSETZBUF, *zcbuf) == -1) {
! 203: LOGERR;
! 204: io_etherClose(eth, zcbuf);
! 205: return -1;
! 206: }
! 207: if (buflen && *buflen)
! 208: *buflen = n;
! 209: #endif
! 210: }
! 211:
! 212: if (csIface)
! 213: strlcpy(szStr, csIface, sizeof szStr);
! 214: else if (io_get1stiface(szStr, sizeof szStr) == -1) {
! 215: io_etherClose(eth, zcbuf);
! 216: return -1;
! 217: }
! 218: memset(&ifr, 0, sizeof ifr);
! 219: strlcpy(ifr.ifr_name, szStr, sizeof ifr.ifr_name);
! 220: if (ioctl(eth, BIOCSETIF, &ifr) == -1) {
! 221: LOGERR;
! 222: io_etherClose(eth, zcbuf);
! 223: return -1;
! 224: }
! 225:
! 226: n = 1;
! 227: if (whdr && ioctl(eth, BIOCSHDRCMPLT, &n) == -1) {
! 228: LOGERR;
! 229: io_etherClose(eth, zcbuf);
! 230: return -1;
! 231: }
! 232: if (ioctl(eth, BIOCIMMEDIATE, &n) == -1) {
! 233: LOGERR;
! 234: io_etherClose(eth, zcbuf);
! 235: return -1;
! 236: }
! 237:
! 238: return eth;
! 239: }
! 240:
! 241: /*
! 242: * io_etherSend() - Send packet to bpf
! 243: *
! 244: * @eth = bpf handle
! 245: * @buf = buffer
! 246: * @buflen = buffer length
! 247: * return: -1 error or !=-1 written bytes
! 248: */
! 249: ssize_t
! 250: io_etherSend(int eth, const void *buf, size_t buflen)
! 251: {
! 252: ssize_t wlen = 0;
! 253:
! 254: if (!buf || !buflen) {
! 255: io_SetErr(EINVAL, "invalid arguments");
! 256: return -1;
! 257: }
! 258:
! 259: wlen = write(eth, buf, buflen);
! 260: if (wlen == -1)
! 261: LOGERR;
! 262: return wlen;
! 263: }
! 264:
! 265: #ifdef __FreeBSD__
! 266: static inline void
! 267: ackZCbuf(struct bpf_zbuf_header *bzh)
! 268: {
! 269: atomic_store_rel_int(&bzh->bzh_user_gen, bzh->bzh_kernel_gen);
! 270: }
! 271:
! 272: static inline int
! 273: chkZCbuf(struct bpf_zbuf_header *bzh)
! 274: {
! 275: /* return true if userspace owns buffer, and false otherwise. */
! 276: return (bzh->bzh_user_gen != atomic_load_acq_int(&bzh->bzh_kernel_gen));
! 277: }
! 278:
! 279: static ssize_t
! 280: nextZCbuf(int eth, struct bpf_zbuf * __restrict zbuf, void * __restrict buf, size_t buflen)
! 281: {
! 282: ssize_t rlen = 0;
! 283: struct bpf_zbuf bz;
! 284: struct bpf_zbuf_header *bzh;
! 285: off_t pos = 0;
! 286:
! 287: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufa;
! 288: if (chkZCbuf(bzh)) {
! 289: rlen = MIN(atomic_load_acq_int(&bzh->bzh_kernel_len), buflen);
! 290: memcpy(buf + pos, zbuf->bz_bufa + sizeof(struct bpf_zbuf_header), rlen);
! 291: ackZCbuf(bzh);
! 292: pos += rlen;
! 293: }
! 294: bzh = (struct bpf_zbuf_header *) zbuf->bz_bufb;
! 295: if (chkZCbuf(bzh)) {
! 296: rlen = MIN(atomic_load_acq_int(&bzh->bzh_kernel_len), buflen);
! 297: memcpy(buf + pos, zbuf->bz_bufb + sizeof(struct bpf_zbuf_header), rlen);
! 298: ackZCbuf(bzh);
! 299: pos += rlen;
! 300: }
! 301:
! 302: if (!pos) {
! 303: if ((rlen = ioctl(eth, BIOCROTZBUF, &bz)) == -1)
! 304: LOGERR;
! 305: } else
! 306: rlen = pos;
! 307: return rlen;
! 308: }
! 309: #endif
! 310:
! 311: /*
! 312: * io_etherRecv() - Receive packet from bpf
! 313: *
! 314: * @eth = bpf handle
! 315: * @buf = buffer
! 316: * @buflen = buffer length
! 317: * @zcbuf = zero copy buffer, if BPF supports it and isn't NULL
! 318: * return: -1 error or !=-1 readed bytes
! 319: */
! 320: ssize_t
! 321: io_etherRecv(int eth, void * __restrict buf, size_t buflen, void * __restrict zcbuf)
! 322: {
! 323: ssize_t rlen = 0;
! 324:
! 325: if (!buf || !buflen) {
! 326: io_SetErr(EINVAL, "invalid arguments");
! 327: return -1;
! 328: }
! 329:
! 330: if (!zcbuf) {
! 331: rlen = read(eth, buf, buflen);
! 332: if (rlen == -1)
! 333: LOGERR;
! 334: } else {
! 335: #ifdef __FreeBSD__
! 336: rlen = nextZCbuf(eth, (struct bpf_zbuf*) zcbuf, buf, buflen);
! 337: if (!rlen)
! 338: rlen = nextZCbuf(eth, (struct bpf_zbuf*) zcbuf, buf, buflen);
! 339: #else
! 340: rlen = -1;
! 341: io_SetErr(ENOTSUP, "bpf zero copy buffer mode is not supported");
! 342: #endif
! 343: }
! 344:
! 345: return rlen;
! 346: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>