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>