1190214Srpaulo/* 2190214Srpaulo * This code is derived from code formerly in pcap-dlpi.c, originally 3190214Srpaulo * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College 4190214Srpaulo * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), 5190214Srpaulo * Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>, 6190214Srpaulo * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>. 7190214Srpaulo */ 8190214Srpaulo 9190214Srpaulo/* 10190214Srpaulo * This file contains dlpi/libdlpi related common functions used 11190214Srpaulo * by pcap-[dlpi,libdlpi].c. 12190214Srpaulo */ 13190214Srpaulo#ifndef lint 14190214Srpaulostatic const char rcsid[] _U_ = 15214518Srpaulo "@(#) $Header: /tcpdump/master/libpcap/dlpisubs.c,v 1.3 2008-12-02 16:40:19 guy Exp $ (LBL)"; 16190214Srpaulo#endif 17190214Srpaulo 18190214Srpaulo#ifdef HAVE_CONFIG_H 19190214Srpaulo#include "config.h" 20190214Srpaulo#endif 21190214Srpaulo 22214518Srpaulo#ifndef DL_IPATM 23214518Srpaulo#define DL_IPATM 0x12 /* ATM Classical IP interface */ 24214518Srpaulo#endif 25214518Srpaulo 26190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 27190214Srpaulo /* 28190214Srpaulo * Size of a bufmod chunk to pass upstream; that appears to be the 29190214Srpaulo * biggest value to which you can set it, and setting it to that value 30190214Srpaulo * (which is bigger than what appears to be the Solaris default of 8192) 31190214Srpaulo * reduces the number of packet drops. 32190214Srpaulo */ 33190214Srpaulo#define CHUNKSIZE 65536 34190214Srpaulo 35190214Srpaulo /* 36190214Srpaulo * Size of the buffer to allocate for packet data we read; it must be 37190214Srpaulo * large enough to hold a chunk. 38190214Srpaulo */ 39190214Srpaulo#define PKTBUFSIZE CHUNKSIZE 40190214Srpaulo 41190214Srpaulo#else /* HAVE_SYS_BUFMOD_H */ 42190214Srpaulo 43190214Srpaulo /* 44190214Srpaulo * Size of the buffer to allocate for packet data we read; this is 45190214Srpaulo * what the value used to be - there's no particular reason why it 46190214Srpaulo * should be tied to MAXDLBUF, but we'll leave it as this for now. 47190214Srpaulo */ 48214518Srpaulo#define MAXDLBUF 8192 49190214Srpaulo#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) 50190214Srpaulo 51190214Srpaulo#endif 52190214Srpaulo 53190214Srpaulo#include <sys/types.h> 54190214Srpaulo#include <sys/time.h> 55190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 56190214Srpaulo#include <sys/bufmod.h> 57190214Srpaulo#endif 58190214Srpaulo#include <sys/dlpi.h> 59190214Srpaulo#include <sys/stream.h> 60190214Srpaulo 61190214Srpaulo#include <errno.h> 62190214Srpaulo#include <memory.h> 63190214Srpaulo#include <stdio.h> 64190214Srpaulo#include <stdlib.h> 65190214Srpaulo#include <string.h> 66190214Srpaulo#include <stropts.h> 67190214Srpaulo#include <unistd.h> 68190214Srpaulo 69190214Srpaulo#include "pcap-int.h" 70190214Srpaulo#include "dlpisubs.h" 71190214Srpaulo 72214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H 73190214Srpaulostatic void pcap_stream_err(const char *, int, char *); 74214518Srpaulo#endif 75190214Srpaulo 76190214Srpaulo/* 77190214Srpaulo * Get the packet statistics. 78190214Srpaulo */ 79190214Srpauloint 80190214Srpaulopcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) 81190214Srpaulo{ 82190214Srpaulo 83190214Srpaulo /* 84190214Srpaulo * "ps_recv" counts packets handed to the filter, not packets 85190214Srpaulo * that passed the filter. As filtering is done in userland, 86190214Srpaulo * this would not include packets dropped because we ran out 87190214Srpaulo * of buffer space; in order to make this more like other 88190214Srpaulo * platforms (Linux 2.4 and later, BSDs with BPF), where the 89190214Srpaulo * "packets received" count includes packets received but dropped 90190214Srpaulo * due to running out of buffer space, and to keep from confusing 91190214Srpaulo * applications that, for example, compute packet drop percentages, 92190214Srpaulo * we also make it count packets dropped by "bufmod" (otherwise we 93190214Srpaulo * might run the risk of the packet drop count being bigger than 94190214Srpaulo * the received-packet count). 95190214Srpaulo * 96190214Srpaulo * "ps_drop" counts packets dropped by "bufmod" because of 97190214Srpaulo * flow control requirements or resource exhaustion; it doesn't 98190214Srpaulo * count packets dropped by the interface driver, or packets 99190214Srpaulo * dropped upstream. As filtering is done in userland, it counts 100190214Srpaulo * packets regardless of whether they would've passed the filter. 101190214Srpaulo * 102190214Srpaulo * These statistics don't include packets not yet read from 103190214Srpaulo * the kernel by libpcap, but they may include packets not 104190214Srpaulo * yet read from libpcap by the application. 105190214Srpaulo */ 106190214Srpaulo *ps = p->md.stat; 107190214Srpaulo 108190214Srpaulo /* 109190214Srpaulo * Add in the drop count, as per the above comment. 110190214Srpaulo */ 111190214Srpaulo ps->ps_recv += ps->ps_drop; 112190214Srpaulo return (0); 113190214Srpaulo} 114190214Srpaulo 115190214Srpaulo/* 116190214Srpaulo * Loop through the packets and call the callback for each packet. 117190214Srpaulo * Return the number of packets read. 118190214Srpaulo */ 119190214Srpauloint 120190214Srpaulopcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, 121190214Srpaulo int count, u_char *bufp, int len) 122190214Srpaulo{ 123190214Srpaulo int n, caplen, origlen; 124190214Srpaulo u_char *ep, *pk; 125190214Srpaulo struct pcap_pkthdr pkthdr; 126190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 127190214Srpaulo struct sb_hdr *sbp; 128190214Srpaulo#ifdef LBL_ALIGN 129190214Srpaulo struct sb_hdr sbhdr; 130190214Srpaulo#endif 131190214Srpaulo#endif 132190214Srpaulo 133190214Srpaulo /* Loop through packets */ 134190214Srpaulo ep = bufp + len; 135190214Srpaulo n = 0; 136190214Srpaulo 137190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 138190214Srpaulo while (bufp < ep) { 139190214Srpaulo /* 140190214Srpaulo * Has "pcap_breakloop()" been called? 141190214Srpaulo * If so, return immediately - if we haven't read any 142190214Srpaulo * packets, clear the flag and return -2 to indicate 143190214Srpaulo * that we were told to break out of the loop, otherwise 144190214Srpaulo * leave the flag set, so that the *next* call will break 145190214Srpaulo * out of the loop without having read any packets, and 146190214Srpaulo * return the number of packets we've processed so far. 147190214Srpaulo */ 148190214Srpaulo if (p->break_loop) { 149190214Srpaulo if (n == 0) { 150190214Srpaulo p->break_loop = 0; 151190214Srpaulo return (-2); 152190214Srpaulo } else { 153190214Srpaulo p->bp = bufp; 154190214Srpaulo p->cc = ep - bufp; 155190214Srpaulo return (n); 156190214Srpaulo } 157190214Srpaulo } 158190214Srpaulo#ifdef LBL_ALIGN 159190214Srpaulo if ((long)bufp & 3) { 160190214Srpaulo sbp = &sbhdr; 161190214Srpaulo memcpy(sbp, bufp, sizeof(*sbp)); 162190214Srpaulo } else 163190214Srpaulo#endif 164190214Srpaulo sbp = (struct sb_hdr *)bufp; 165190214Srpaulo p->md.stat.ps_drop = sbp->sbh_drops; 166190214Srpaulo pk = bufp + sizeof(*sbp); 167190214Srpaulo bufp += sbp->sbh_totlen; 168190214Srpaulo origlen = sbp->sbh_origlen; 169190214Srpaulo caplen = sbp->sbh_msglen; 170190214Srpaulo#else 171190214Srpaulo origlen = len; 172190214Srpaulo caplen = min(p->snapshot, len); 173190214Srpaulo pk = bufp; 174190214Srpaulo bufp += caplen; 175190214Srpaulo#endif 176190214Srpaulo ++p->md.stat.ps_recv; 177190214Srpaulo if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { 178190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 179190214Srpaulo pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; 180190214Srpaulo pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; 181190214Srpaulo#else 182190214Srpaulo (void) gettimeofday(&pkthdr.ts, NULL); 183190214Srpaulo#endif 184190214Srpaulo pkthdr.len = origlen; 185190214Srpaulo pkthdr.caplen = caplen; 186190214Srpaulo /* Insure caplen does not exceed snapshot */ 187190214Srpaulo if (pkthdr.caplen > p->snapshot) 188190214Srpaulo pkthdr.caplen = p->snapshot; 189190214Srpaulo (*callback)(user, &pkthdr, pk); 190190214Srpaulo if (++n >= count && count >= 0) { 191190214Srpaulo p->cc = ep - bufp; 192190214Srpaulo p->bp = bufp; 193190214Srpaulo return (n); 194190214Srpaulo } 195190214Srpaulo } 196190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 197190214Srpaulo } 198190214Srpaulo#endif 199190214Srpaulo p->cc = 0; 200190214Srpaulo return (n); 201190214Srpaulo} 202190214Srpaulo 203190214Srpaulo/* 204190214Srpaulo * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. 205190214Srpaulo */ 206190214Srpauloint 207190214Srpaulopcap_process_mactype(pcap_t *p, u_int mactype) 208190214Srpaulo{ 209190214Srpaulo int retv = 0; 210190214Srpaulo 211190214Srpaulo switch (mactype) { 212190214Srpaulo 213190214Srpaulo case DL_CSMACD: 214190214Srpaulo case DL_ETHER: 215190214Srpaulo p->linktype = DLT_EN10MB; 216190214Srpaulo p->offset = 2; 217190214Srpaulo /* 218190214Srpaulo * This is (presumably) a real Ethernet capture; give it a 219190214Srpaulo * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 220190214Srpaulo * that an application can let you choose it, in case you're 221190214Srpaulo * capturing DOCSIS traffic that a Cisco Cable Modem 222190214Srpaulo * Termination System is putting out onto an Ethernet (it 223190214Srpaulo * doesn't put an Ethernet header onto the wire, it puts raw 224190214Srpaulo * DOCSIS frames out on the wire inside the low-level 225190214Srpaulo * Ethernet framing). 226190214Srpaulo */ 227190214Srpaulo p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); 228190214Srpaulo /* 229190214Srpaulo * If that fails, just leave the list empty. 230190214Srpaulo */ 231190214Srpaulo if (p->dlt_list != NULL) { 232190214Srpaulo p->dlt_list[0] = DLT_EN10MB; 233190214Srpaulo p->dlt_list[1] = DLT_DOCSIS; 234190214Srpaulo p->dlt_count = 2; 235190214Srpaulo } 236190214Srpaulo break; 237190214Srpaulo 238190214Srpaulo case DL_FDDI: 239190214Srpaulo p->linktype = DLT_FDDI; 240190214Srpaulo p->offset = 3; 241190214Srpaulo break; 242190214Srpaulo 243190214Srpaulo case DL_TPR: 244190214Srpaulo /* XXX - what about DL_TPB? Is that Token Bus? */ 245190214Srpaulo p->linktype = DLT_IEEE802; 246190214Srpaulo p->offset = 2; 247190214Srpaulo break; 248190214Srpaulo 249190214Srpaulo#ifdef HAVE_SOLARIS 250190214Srpaulo case DL_IPATM: 251190214Srpaulo p->linktype = DLT_SUNATM; 252190214Srpaulo p->offset = 0; /* works for LANE and LLC encapsulation */ 253190214Srpaulo break; 254190214Srpaulo#endif 255190214Srpaulo 256190214Srpaulo default: 257190214Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u", 258190214Srpaulo mactype); 259190214Srpaulo retv = -1; 260190214Srpaulo } 261190214Srpaulo 262190214Srpaulo return (retv); 263190214Srpaulo} 264190214Srpaulo 265190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 266190214Srpaulo/* 267190214Srpaulo * Push and configure the buffer module. Returns -1 for error, otherwise 0. 268190214Srpaulo */ 269190214Srpauloint 270190214Srpaulopcap_conf_bufmod(pcap_t *p, int snaplen, int timeout) 271190214Srpaulo{ 272190214Srpaulo int retv = 0; 273190214Srpaulo 274190214Srpaulo bpf_u_int32 ss, chunksize; 275190214Srpaulo 276190214Srpaulo /* Non-standard call to get the data nicely buffered. */ 277190214Srpaulo if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 278190214Srpaulo pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); 279190214Srpaulo retv = -1; 280190214Srpaulo } 281190214Srpaulo 282190214Srpaulo ss = snaplen; 283190214Srpaulo if (ss > 0 && 284190214Srpaulo strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 285190214Srpaulo pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); 286190214Srpaulo retv = -1; 287190214Srpaulo } 288190214Srpaulo 289190214Srpaulo /* Set up the bufmod timeout. */ 290190214Srpaulo if (timeout != 0) { 291190214Srpaulo struct timeval to; 292190214Srpaulo 293190214Srpaulo to.tv_sec = timeout / 1000; 294190214Srpaulo to.tv_usec = (timeout * 1000) % 1000000; 295190214Srpaulo if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 296190214Srpaulo pcap_stream_err("SBIOCSTIME", errno, p->errbuf); 297190214Srpaulo retv = -1; 298190214Srpaulo } 299190214Srpaulo } 300190214Srpaulo 301190214Srpaulo /* Set the chunk length. */ 302190214Srpaulo chunksize = CHUNKSIZE; 303190214Srpaulo if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) 304190214Srpaulo != 0) { 305190214Srpaulo pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); 306190214Srpaulo retv = -1; 307190214Srpaulo } 308190214Srpaulo 309190214Srpaulo return (retv); 310190214Srpaulo} 311190214Srpaulo#endif /* HAVE_SYS_BUFMOD_H */ 312190214Srpaulo 313190214Srpaulo/* 314190214Srpaulo * Allocate data buffer. Returns -1 if memory allocation fails, else 0. 315190214Srpaulo */ 316190214Srpauloint 317190214Srpaulopcap_alloc_databuf(pcap_t *p) 318190214Srpaulo{ 319190214Srpaulo p->bufsize = PKTBUFSIZE; 320190214Srpaulo p->buffer = (u_char *)malloc(p->bufsize + p->offset); 321190214Srpaulo if (p->buffer == NULL) { 322190214Srpaulo strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 323190214Srpaulo return (-1); 324190214Srpaulo } 325190214Srpaulo 326190214Srpaulo return (0); 327190214Srpaulo} 328190214Srpaulo 329190214Srpaulo/* 330190214Srpaulo * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise 331190214Srpaulo * length of returned data on success. 332190214Srpaulo */ 333190214Srpauloint 334190214Srpaulostrioctl(int fd, int cmd, int len, char *dp) 335190214Srpaulo{ 336190214Srpaulo struct strioctl str; 337190214Srpaulo int retv; 338190214Srpaulo 339190214Srpaulo str.ic_cmd = cmd; 340190214Srpaulo str.ic_timout = -1; 341190214Srpaulo str.ic_len = len; 342190214Srpaulo str.ic_dp = dp; 343190214Srpaulo if ((retv = ioctl(fd, I_STR, &str)) < 0) 344190214Srpaulo return (retv); 345190214Srpaulo 346190214Srpaulo return (str.ic_len); 347190214Srpaulo} 348190214Srpaulo 349214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H 350190214Srpaulo/* 351190214Srpaulo * Write stream error message to errbuf. 352190214Srpaulo */ 353190214Srpaulostatic void 354190214Srpaulopcap_stream_err(const char *func, int err, char *errbuf) 355190214Srpaulo{ 356190214Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); 357190214Srpaulo} 358214518Srpaulo#endif 359