diff options
Diffstat (limited to 'contrib/libpcap/pcap-linux.c')
-rw-r--r-- | contrib/libpcap/pcap-linux.c | 140 |
1 files changed, 116 insertions, 24 deletions
diff --git a/contrib/libpcap/pcap-linux.c b/contrib/libpcap/pcap-linux.c index fe56d05..d01899a 100644 --- a/contrib/libpcap/pcap-linux.c +++ b/contrib/libpcap/pcap-linux.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996 + * Copyright (c) 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -20,7 +20,7 @@ */ #ifndef lint static const char rcsid[] = - "@(#) $Header: pcap-linux.c,v 1.4 96/12/10 23:15:00 leres Exp $ (LBL)"; + "@(#) $Header: pcap-linux.c,v 1.15 97/10/02 22:39:37 leres Exp $ (LBL)"; #endif #include <sys/param.h> @@ -29,10 +29,17 @@ static const char rcsid[] = #include <sys/time.h> #include <net/if.h> +#ifdef HAVE_NET_IF_ARP_H +#include <net/if_arp.h> +#else +#include <linux/if_arp.h> +#endif +#include <linux/if_ether.h> #include <netinet/in.h> #include <errno.h> +#include <malloc.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -67,12 +74,12 @@ pcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user) struct sockaddr from; int fromlen; - bp = (char *)p->buffer; + bp = p->buffer + p->offset; bufsize = p->bufsize; if (p->md.pad > 0) { + memset(bp, 0, p->md.pad); bp += p->md.pad; bufsize -= p->md.pad; - memset(p->buffer, 0, p->md.pad); } again: @@ -96,7 +103,7 @@ again: /* If we need have leading zero bytes, adjust count */ cc += p->md.pad; - bp = p->buffer; + bp = p->buffer + p->offset; /* If we need to step over leading junk, adjust count and pointer */ cc -= p->md.skip; @@ -136,46 +143,131 @@ pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) register int fd, broadcast; register pcap_t *p; struct ifreq ifr; + struct sockaddr sa; p = (pcap_t *)malloc(sizeof(*p)); if (p == NULL) { sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); return (NULL); } - memset((char *)p, 0, sizeof(*p)); + memset(p, 0, sizeof(*p)); fd = -1; - /* XXX hack - map device name to link layer type */ + fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); + if (fd < 0) { + sprintf(ebuf, "socket: %s", pcap_strerror(errno)); + goto bad; + } + p->fd = fd; + + /* Bind to the interface name */ + memset(&sa, 0, sizeof(sa)); + sa.sa_family = AF_INET; + (void)strncpy(sa.sa_data, device, sizeof(sa.sa_data)); + if (bind(p->fd, &sa, sizeof(sa))) { + sprintf(ebuf, "bind: %s: %s", device, pcap_strerror(errno)); + goto bad; + } + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(p->fd, SIOCGIFHWADDR, &ifr) < 0 ) { + sprintf(ebuf, "SIOCGIFHWADDR: %s", pcap_strerror(errno)); + goto bad; + } broadcast = 0; - if (strncmp("eth", device, 3) == 0) { + switch (ifr.ifr_hwaddr.sa_family) { + + case ARPHRD_ETHER: + case ARPHRD_METRICOM: p->linktype = DLT_EN10MB; + p->offset = 2; + ++broadcast; + break; + + case ARPHRD_EETHER: + p->linktype = DLT_EN3MB; + ++broadcast; + break; + + case ARPHRD_AX25: + p->linktype = DLT_AX25; ++broadcast; - } else if (strncmp("sl", device, 2) == 0) { - p->linktype = DLT_SLIP; - p->md.pad = 16; - } else if (strncmp("ppp", device, 3) == 0) { - p->linktype = DLT_PPP; - p->md.pad = 4; - } else if (strncmp("lo", device, 2) == 0) { + break; + + case ARPHRD_PRONET: + p->linktype = DLT_PRONET; + break; + + case ARPHRD_CHAOS: + p->linktype = DLT_CHAOS; + break; + + case ARPHRD_IEEE802: + p->linktype = DLT_IEEE802; + ++broadcast; + break; + + case ARPHRD_ARCNET: + p->linktype = DLT_ARCNET; + ++broadcast; + break; + + case ARPHRD_SLIP: + case ARPHRD_CSLIP: + case ARPHRD_SLIP6: + case ARPHRD_CSLIP6: + case ARPHRD_PPP: + p->linktype = DLT_RAW; + break; + + case ARPHRD_LOOPBACK: p->linktype = DLT_NULL; p->md.pad = 2; p->md.skip = 12; - } else { - sprintf(ebuf, "linux: unknown physical layer type"); + break; + +#ifdef ARPHRD_FDDI + /* Not all versions of the kernel has this define */ + case ARPHRD_FDDI: + p->linktype = DLT_FDDI; + ++broadcast; + break; +#endif + +#ifdef notdef + case ARPHRD_LOCALTLK: + case ARPHRD_NETROM: + case ARPHRD_APPLETLK: + case ARPHRD_DLCI: + case ARPHRD_RSRVD: + case ARPHRD_ADAPT: + case ARPHRD_TUNNEL: + case ARPHRD_TUNNEL6: + case ARPHRD_FRAD: + case ARPHRD_SKIP: + /* XXX currently do not know what to do with these... */ + abort(); +#endif + + default: + sprintf(ebuf, "unknown physical layer type 0x%x", + ifr.ifr_hwaddr.sa_family); goto bad; } - /* Linux is full of magic numbers */ - fd = socket(PF_INET, SOCK_PACKET, htons(0x0003)); - if (fd < 0) { - sprintf(ebuf, "linux socket: %s", pcap_strerror(errno)); + /* Base the buffer size on the interface MTU */ + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); + if (ioctl(p->fd, SIOCGIFMTU, &ifr) < 0 ) { + sprintf(ebuf, "SIOCGIFMTU: %s", pcap_strerror(errno)); goto bad; } - p->fd = fd; + /* Leave room for link header (which is never large under linux...) */ + p->bufsize = ifr.ifr_mtu + 64; - p->bufsize = 4096; /* XXX */ - p->buffer = (u_char *)malloc(p->bufsize); + p->buffer = (u_char *)malloc(p->bufsize + p->offset); if (p->buffer == NULL) { sprintf(ebuf, "malloc: %s", pcap_strerror(errno)); goto bad; |