File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_link_bpf.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:11:38 2023 UTC (9 months, 1 week ago) by misho
Branches: libnet, MAIN
CVS tags: v1_2p1, HEAD
Version 1.2p1

    1: /*
    2:  *  $Id: libnet_link_bpf.c,v 1.1.1.4 2023/09/27 11:11:38 misho Exp $
    3:  *
    4:  *  libnet
    5:  *  libnet_link_bpf.c - low-level bpf routines
    6:  *
    7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
    8:  *  All rights reserved.
    9:  *
   10:  * Copyright (c) 1993, 1994, 1995, 1996, 1998
   11:  *	The Regents of the University of California.  All rights reserved.
   12:  *
   13:  * Redistribution and use in source and binary forms, with or without
   14:  * modification, are permitted provided that: (1) source code distributions
   15:  * retain the above copyright notice and this paragraph in its entirety, (2)
   16:  * distributions including binary code include the above copyright notice and
   17:  * this paragraph in its entirety in the documentation or other materials
   18:  * provided with the distribution, and (3) all advertising materials mentioning
   19:  * features or use of this software display the following acknowledgement:
   20:  * ``This product includes software developed by the University of California,
   21:  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   22:  * the University nor the names of its contributors may be used to endorse
   23:  * or promote products derived from this software without specific prior
   24:  * written permission.
   25:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   26:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   27:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   28:  */
   29: 
   30: #include "common.h"
   31: 
   32: #include <sys/param.h>  /* optionally get BSD define */
   33: #if !defined(__OpenBSD__) && !defined(__FreeBSD__)
   34: #include <sys/timeb.h>
   35: #endif
   36: #include <sys/file.h>
   37: #include <sys/ioctl.h>
   38: 
   39: #include <sys/types.h>
   40: #include <sys/time.h>
   41: #include <net/bpf.h>
   42: 
   43: #include <sys/sysctl.h>
   44: #include <net/route.h>
   45: #include <net/if_dl.h>
   46: #include <net/if_types.h>
   47: #include "../include/gnuc.h"
   48: 
   49: #include "../include/bpf.h"
   50: 
   51: #ifdef HAVE_OS_PROTO_H
   52: #include "../include/os-proto.h"
   53: #endif
   54: 
   55: int
   56: libnet_bpf_open(char *err_buf)
   57: {
   58:     int i, fd;
   59:     char device[] = "/dev/bpf000";
   60: 
   61:     /*
   62:      *  Go through all the minors and find one that isn't in use.
   63:      */
   64:     for (i = 0; i < 1000; i++)
   65:     {
   66:         snprintf(device, sizeof(device), "/dev/bpf%d", i);
   67: 
   68:         fd = open(device, O_RDWR);
   69:         if (fd == -1 && errno == EBUSY)
   70:         {
   71:             /*
   72:              *  Device is busy.
   73:              */
   74:             continue;
   75:         }
   76:         else
   77:         {
   78:             /*
   79:              *  Either we've got a valid file descriptor, or errno is not
   80:              *  EBUSY meaning we've probably run out of devices.
   81:              */
   82:             break;
   83:         }
   84:     }
   85: 
   86:     if (fd == -1)
   87:     {
   88:         snprintf(err_buf, LIBNET_ERRBUF_SIZE, "%s(): open(): (%s): %s",
   89:                 __func__, device, strerror(errno));
   90:     }
   91:     return (fd);
   92: }
   93: 
   94: 
   95: int
   96: libnet_open_link(libnet_t *l)
   97: {
   98:     struct ifreq ifr;
   99:     struct bpf_version bv;
  100:     uint v;
  101: 
  102: #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
  103:     uint spoof_eth_src = 1;
  104: #endif
  105: 
  106:     if (l == NULL)
  107:     { 
  108:         return (-1);
  109:     } 
  110: 
  111:     if (l->device == NULL)
  112:     {
  113:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): NULL device", 
  114:                 __func__);
  115:         goto bad;
  116:     }
  117: 
  118:     l->fd = libnet_bpf_open((char*)l->err_buf);
  119:     if (l->fd == -1)
  120:     {
  121:         goto bad;
  122:     }
  123: 
  124:     /*
  125:      *  Get bpf version.
  126:      */
  127:     if (ioctl(l->fd, BIOCVERSION, (caddr_t)&bv) < 0)
  128:     {
  129:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCVERSION: %s",
  130:                 __func__, strerror(errno));
  131:         goto bad;
  132:     }
  133: 
  134:     if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION)
  135:     {
  136:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  137:                 "%s(): kernel bpf filter out of date", __func__);
  138:         goto bad;
  139:     }
  140: 
  141:     /*
  142:      *  Attach network interface to bpf device.
  143:      */
  144: 	strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) - 1);
  145:     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
  146: 
  147:     if (ioctl(l->fd, BIOCSETIF, (caddr_t)&ifr) == -1)
  148:     {
  149:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSETIF: (%s): %s",
  150:                 __func__, l->device, strerror(errno));
  151:         goto bad;
  152:     }
  153: 
  154:     /*
  155:      *  Get the data link-layer type.
  156:      */
  157:     if (ioctl(l->fd, BIOCGDLT, (caddr_t)&v) == -1)
  158:     {
  159:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCGDLT: %s",
  160:                 __func__, strerror(errno));
  161:         goto bad;
  162:     }
  163: 
  164:     /*
  165:      *  NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
  166:      *  automatic filling of the link level source address.
  167:      */
  168: #if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
  169:     if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
  170:     {
  171:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s",
  172:                 __func__, strerror(errno));
  173:         goto bad;
  174:     }
  175: #endif
  176: 
  177:     /*
  178:      *  Assign link type and offset.
  179:      */
  180:     switch (v)
  181:     {
  182:         case DLT_SLIP:
  183:             l->link_offset = 0x10;
  184:             break;
  185:         case DLT_RAW:
  186:             l->link_offset = 0x0;
  187:             break;
  188:         case DLT_PPP:
  189:             l->link_offset = 0x04;
  190:             break;
  191:         case DLT_EN10MB:
  192:         default:
  193:             l->link_offset = 0xe;     /* default to ethernet */
  194:             break;
  195:     }
  196: #if _BSDI_VERSION - 0 >= 199510
  197:     switch (v)
  198:     {
  199:         case DLT_SLIP:
  200:             v = DLT_SLIP_BSDOS;
  201:             l->link_offset = 0x10;
  202:             break;
  203:         case DLT_PPP:
  204:             v = DLT_PPP_BSDOS;
  205:             l->link_offset = 0x04;
  206:             break;
  207:     }
  208: #endif
  209:     l->link_type = v;
  210: 
  211:     return (1);
  212: 
  213: bad:
  214:     if (l->fd > 0)
  215:     {
  216:         close(l->fd);      /* this can fail ok */
  217:     }
  218:     return (-1);
  219: }
  220: 
  221: 
  222: int
  223: libnet_close_link(libnet_t *l)
  224: {
  225:     if (close(l->fd) == 0)
  226:     {
  227:         return (1);
  228:     }
  229:     else
  230:     {
  231:         return (-1);
  232:     }
  233: }
  234: 
  235: 
  236: int
  237: libnet_write_link(libnet_t *l, const uint8_t *packet, uint32_t size)
  238: {
  239:     int c;
  240: 
  241:     if (l == NULL)
  242:     { 
  243:         return (-1);
  244:     } 
  245: 
  246:     c = write(l->fd, packet, size);
  247:     if (c != size)
  248:     {
  249:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  250:                 "%s(): %d bytes written (%s)", __func__, c, strerror(errno));
  251:     }
  252:     return (c);
  253: }
  254: 
  255: 
  256: struct libnet_ether_addr *
  257: libnet_get_hwaddr(libnet_t *l)
  258: {
  259:     int mib[6];
  260:     size_t len;
  261:     int8_t *buf, *next, *end;
  262:     struct if_msghdr *ifm;
  263:     struct sockaddr_dl *sdl;
  264: 
  265:     mib[0] = CTL_NET;
  266:     mib[1] = AF_ROUTE;
  267:     mib[2] = 0;
  268:     mib[3] = AF_LINK;
  269:     mib[4] = NET_RT_IFLIST;
  270:     mib[5] = 0;
  271: 
  272:     if (l == NULL)
  273:     { 
  274:         return (NULL);
  275:     } 
  276: 
  277:     if (l->device == NULL)
  278:     {           
  279:         if (libnet_select_device(l) == -1)
  280:         {
  281:             /* err msg set in libnet_select_device */ 
  282:             return (NULL);
  283:         }
  284:     }
  285: 
  286:     if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
  287:     {
  288:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s",
  289:                 __func__, strerror(errno));
  290:         return (NULL);
  291:     }
  292: 
  293:     buf = (int8_t *)malloc(len);
  294:     if (buf == NULL)
  295:     {
  296:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s",
  297:                 __func__, strerror(errno));
  298:         return (NULL);
  299:     }
  300:     if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
  301:     {
  302:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s",
  303:                 __func__, strerror(errno));
  304:         free(buf);
  305:         return (NULL);
  306:     }
  307:     end = buf + len;
  308: 
  309:     for (next = buf ; next < end ; next += ifm->ifm_msglen)
  310:     {
  311:         ifm = (struct if_msghdr *)next;
  312: 
  313:         if (ifm->ifm_version != RTM_VERSION)
  314:             continue;
  315: 
  316:         if (ifm->ifm_type == RTM_IFINFO)
  317:         {
  318:             sdl = (struct sockaddr_dl *)(ifm + 1);
  319:             if (sdl->sdl_type != IFT_ETHER
  320: #ifdef IFT_FASTETHER
  321:                 && sdl->sdl_type != IFT_FASTETHER
  322: #endif
  323: #ifdef IFT_FASTETHERFX
  324:                 && sdl->sdl_type != IFT_FASTETHERFX
  325: #endif
  326: #ifdef IFT_GIGABITETHERNET
  327:                 && sdl->sdl_type != IFT_GIGABITETHERNET
  328: #endif
  329: 
  330:                 && sdl->sdl_type != IFT_L2VLAN)
  331:                 continue;
  332:             if (sdl->sdl_nlen == strlen(l->device)
  333:                 && strncmp(&sdl->sdl_data[0], l->device, sdl->sdl_nlen) == 0)
  334:             {
  335:                 memcpy(l->link_addr.ether_addr_octet, LLADDR(sdl), ETHER_ADDR_LEN);
  336:                 break;
  337:             }
  338:         }
  339:     }
  340:     free(buf);
  341:     if (next == end)
  342:     {
  343:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  344:                  "%s(): interface %s of known type not found.",
  345:                  __func__, l->device);
  346:         return NULL;
  347:     }
  348: 
  349:     return (&l->link_addr);
  350: }
  351: 
  352: /**
  353:  * Local Variables:
  354:  *  indent-tabs-mode: nil
  355:  *  c-file-style: "stroustrup"
  356:  * End:
  357:  */

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