File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libnet / src / libnet_link_linux.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 11:54:42 2013 UTC (10 years, 11 months ago) by misho
Branches: libnet, MAIN
CVS tags: v1_1_6p5, v1_1_6p4, v1_1_6p0, v1_1_6, HEAD
1.1.6

    1: /*
    2:  *  $Id: libnet_link_linux.c,v 1.1.1.2 2013/07/22 11:54:42 misho Exp $
    3:  *
    4:  *  libnet 1.1
    5:  *  libnet_link_linux.c - linux packet socket and pack socket routines
    6:  *
    7:  *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
    8:  *  All rights reserved.
    9:  *
   10:  * Redistribution and use in source and binary forms, with or without
   11:  * modification, are permitted provided that: (1) source code distributions
   12:  * retain the above copyright notice and this paragraph in its entirety, (2)
   13:  * distributions including binary code include the above copyright notice and
   14:  * this paragraph in its entirety in the documentation or other materials
   15:  * provided with the distribution, and (3) all advertising materials mentioning
   16:  * features or use of this software display the following acknowledgement:
   17:  * ``This product includes software developed by the University of California,
   18:  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
   19:  * the University nor the names of its contributors may be used to endorse
   20:  * or promote products derived from this software without specific prior
   21:  * written permission.
   22:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
   23:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
   24:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   25:  */
   26: 
   27: #if (HAVE_CONFIG_H)
   28: #include "../include/config.h"
   29: #endif
   30: #include <sys/time.h>
   31: 
   32: #include <net/if.h>
   33: #if (__GLIBC__)
   34: #include <netinet/if_ether.h>
   35: #include <net/if_arp.h>
   36: #else
   37: #include <linux/if_arp.h>
   38: #include <linux/if_ether.h>
   39: #endif
   40: 
   41: #if (HAVE_PACKET_SOCKET)
   42: #ifndef SOL_PACKET
   43: #define SOL_PACKET 263
   44: #endif  /* SOL_PACKET */
   45: #if __GLIBC__ >= 2 && __GLIBC_MINOR >= 1
   46: #include <netpacket/packet.h>
   47: #include <net/ethernet.h>     /* the L2 protocols */
   48: #else
   49: #include <asm/types.h>
   50: #include <linux/if_packet.h>
   51: #include <linux/if_ether.h>   /* The L2 protocols */
   52: #endif
   53: #endif  /* HAVE_PACKET_SOCKET */
   54: 
   55: #include "../include/libnet.h"
   56: 
   57: /* These should not vary across linux systems, and are only defined in
   58:  * <pcap-bpf.h>, included from <pcap.h>, but since we have no other dependency
   59:  * on libpcap right now, define locally. I'm not sure if this is a good idea,
   60:  * but we'll try.
   61:  */
   62: #define DLT_PRONET	4	/* Proteon ProNET Token Ring */
   63: #define DLT_FDDI	10	/* FDDI */
   64: #define DLT_RAW		12	/* raw IP */
   65: 
   66: #include "../include/gnuc.h"
   67: #ifdef HAVE_OS_PROTO_H
   68: #include "../include/os-proto.h"
   69: #endif
   70: 
   71: 
   72: int
   73: libnet_open_link(libnet_t *l)
   74: {
   75:     struct ifreq ifr;
   76:     int n = 1;
   77: 
   78:     if (l == NULL)
   79:     { 
   80:         return (-1);
   81:     } 
   82: 
   83: #if (HAVE_PACKET_SOCKET)
   84:     l->fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
   85: #else
   86:     l->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
   87: #endif
   88:     if (l->fd == -1)
   89:     {
   90:         if (errno == EPERM) {
   91:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   92:                      "%s(): UID/EUID 0 or capability CAP_NET_RAW required",
   93:                      __func__);
   94: 
   95:         } else {
   96:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
   97:                      "socket: %s", strerror(errno));
   98:         }
   99:         goto bad;
  100:     }
  101: 
  102:     memset(&ifr, 0, sizeof (ifr));
  103:     strncpy(ifr.ifr_name, l->device, sizeof (ifr.ifr_name) -1);
  104:     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
  105: 
  106:     if (ioctl(l->fd, SIOCGIFHWADDR, &ifr) < 0 )
  107:     {
  108:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  109:                 "SIOCGIFHWADDR: %s", strerror(errno));
  110:         goto bad;
  111:     }
  112: 
  113:     switch (ifr.ifr_hwaddr.sa_family)
  114:     {
  115:         case ARPHRD_ETHER:
  116:         case ARPHRD_METRICOM:
  117: #ifdef ARPHRD_LOOPBACK
  118:         case ARPHRD_LOOPBACK:   
  119: #endif
  120:             l->link_type = DLT_EN10MB;
  121:             l->link_offset = 0xe;
  122:             break;
  123:         case ARPHRD_SLIP:
  124:         case ARPHRD_CSLIP:
  125:         case ARPHRD_SLIP6:
  126:         case ARPHRD_CSLIP6:
  127:         case ARPHRD_PPP:
  128:             l->link_type = DLT_RAW;
  129:             break;
  130:         case ARPHRD_FDDI:
  131:             l->link_type   = DLT_FDDI;
  132:             l->link_offset = 0x15;
  133:             break;
  134:         /* Token Ring */
  135:         case ARPHRD_IEEE802:
  136:         case ARPHRD_IEEE802_TR:
  137:         case ARPHRD_PRONET:
  138:             l->link_type   = DLT_PRONET;
  139:             l->link_offset = 0x16;
  140:             break;
  141: 
  142:         default:
  143:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  144:                 "unknown physical layer type 0x%x\n",
  145:                 ifr.ifr_hwaddr.sa_family);
  146:         goto bad;
  147:     }
  148: #ifdef SO_BROADCAST
  149: /*
  150:  * man 7 socket
  151:  *
  152:  * Set or get the broadcast flag. When  enabled,  datagram  sockets
  153:  * receive packets sent to a broadcast address and they are allowed
  154:  * to send packets to a broadcast  address.   This  option  has  no
  155:  * effect on stream-oriented sockets.
  156:  */
  157:     if (setsockopt(l->fd, SOL_SOCKET, SO_BROADCAST, &n, sizeof(n)) == -1)
  158:     {
  159:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  160: 		 "%s: set SO_BROADCAST failed: %s\n",
  161: 		 __func__, strerror(errno));
  162:         goto bad;
  163:     }
  164: #endif  /*  SO_BROADCAST  */
  165: 
  166:     return (1);
  167: 
  168: bad:
  169:     if (l->fd >= 0)
  170:     {
  171:         close(l->fd);
  172:     }
  173:     return (-1);
  174: }
  175: 
  176: 
  177: int
  178: libnet_close_link(libnet_t *l)
  179: {
  180:     if (close(l->fd) == 0)
  181:     {
  182:         return (1);
  183:     }
  184:     else
  185:     {
  186:         return (-1);
  187:     }
  188: }
  189: 
  190: 
  191: #if (HAVE_PACKET_SOCKET)
  192: static int
  193: get_iface_index(int fd, const char *device)
  194: {
  195:     struct ifreq ifr;
  196:  
  197:     /* memset(&ifr, 0, sizeof(ifr)); */
  198:     strncpy (ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1);
  199:     ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
  200:  
  201:     if (ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
  202:     {
  203:         return (-1);
  204:     }
  205:  
  206:     return ifr.ifr_ifindex;
  207: }
  208: #endif
  209: 
  210: 
  211: int
  212: libnet_write_link(libnet_t *l, const uint8_t *packet, uint32_t size)
  213: {
  214:     int c;
  215: #if (HAVE_PACKET_SOCKET)
  216:     struct sockaddr_ll sa;
  217: #else
  218:     struct sockaddr sa;
  219: #endif
  220: 
  221:     if (l == NULL)
  222:     { 
  223:         return (-1);
  224:     }
  225: 
  226:     memset(&sa, 0, sizeof (sa));
  227: #if (HAVE_PACKET_SOCKET)
  228:     sa.sll_family    = AF_PACKET;
  229:     sa.sll_ifindex   = get_iface_index(l->fd, l->device);
  230:     if (sa.sll_ifindex == -1)
  231:     {
  232:         return (-1);
  233:     }
  234:     sa.sll_protocol  = htons(ETH_P_ALL);
  235: #else
  236: 	strncpy(sa.sa_data, l->device, sizeof (sa.sa_data) - 1);
  237:     sa.sa_data[sizeof (sa.sa_data) - 1] = 0;
  238: #endif
  239: 
  240:     c = sendto(l->fd, packet, size, 0,
  241:             (struct sockaddr *)&sa, sizeof (sa));
  242:     if (c != size)
  243:     {
  244:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  245:                 "libnet_write_link(): only %d bytes written (%s)\n", c,
  246:                 strerror(errno));
  247:     }
  248:     return (c);
  249: }
  250: 
  251: 
  252: struct libnet_ether_addr *
  253: libnet_get_hwaddr(libnet_t *l)
  254: {
  255:     int fd;
  256:     struct ifreq ifr;
  257:     struct libnet_ether_addr *eap;
  258:     /*
  259:      *  XXX - non-re-entrant!
  260:      */
  261:     static struct libnet_ether_addr ea;
  262: 
  263:     if (l == NULL)
  264:     { 
  265:         return (NULL);
  266:     } 
  267: 
  268:     if (l->device == NULL)
  269:     {           
  270:         if (libnet_select_device(l) == -1)
  271:         {   
  272:             snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  273:                     "libnet_get_hwaddr: can't figure out a device to use\n");
  274:             return (NULL);
  275:         }
  276:     }
  277: 
  278:     /*
  279:      *  Create dummy socket to perform an ioctl upon.
  280:      */
  281:     fd = socket(AF_INET, SOCK_DGRAM, 0);
  282:     if (fd < 0)
  283:     {
  284:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  285:                 "socket: %s", strerror(errno));
  286:         goto bad;
  287:     }
  288: 
  289:     memset(&ifr, 0, sizeof(ifr));
  290:     eap = &ea;
  291:    	strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) - 1);
  292:     ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
  293: 
  294:     if (ioctl(fd, SIOCGIFHWADDR, (int8_t *)&ifr) < 0)
  295:     {
  296:         close(fd);
  297:         snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
  298:                 "ioctl: %s", strerror(errno));
  299:         goto bad;
  300:     }
  301:     memcpy(eap, &ifr.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
  302:     close(fd);
  303:     return (eap);
  304: 
  305: bad:
  306:     return (NULL);
  307: }
  308: 
  309: /* ---- Emacs Variables ----
  310:  * Local Variables:
  311:  * c-basic-offset: 4
  312:  * indent-tabs-mode: nil
  313:  * End:
  314:  */
  315: 
  316: /* EOF */

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