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 14190214Srpaulo#ifdef HAVE_CONFIG_H 15190214Srpaulo#include "config.h" 16190214Srpaulo#endif 17190214Srpaulo 18214518Srpaulo#ifndef DL_IPATM 19214518Srpaulo#define DL_IPATM 0x12 /* ATM Classical IP interface */ 20214518Srpaulo#endif 21214518Srpaulo 22190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 23190214Srpaulo /* 24190214Srpaulo * Size of a bufmod chunk to pass upstream; that appears to be the 25190214Srpaulo * biggest value to which you can set it, and setting it to that value 26190214Srpaulo * (which is bigger than what appears to be the Solaris default of 8192) 27190214Srpaulo * reduces the number of packet drops. 28190214Srpaulo */ 29190214Srpaulo#define CHUNKSIZE 65536 30190214Srpaulo 31190214Srpaulo /* 32190214Srpaulo * Size of the buffer to allocate for packet data we read; it must be 33190214Srpaulo * large enough to hold a chunk. 34190214Srpaulo */ 35190214Srpaulo#define PKTBUFSIZE CHUNKSIZE 36190214Srpaulo 37190214Srpaulo#else /* HAVE_SYS_BUFMOD_H */ 38190214Srpaulo 39190214Srpaulo /* 40190214Srpaulo * Size of the buffer to allocate for packet data we read; this is 41190214Srpaulo * what the value used to be - there's no particular reason why it 42190214Srpaulo * should be tied to MAXDLBUF, but we'll leave it as this for now. 43190214Srpaulo */ 44214518Srpaulo#define MAXDLBUF 8192 45190214Srpaulo#define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) 46190214Srpaulo 47190214Srpaulo#endif 48190214Srpaulo 49190214Srpaulo#include <sys/types.h> 50190214Srpaulo#include <sys/time.h> 51190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 52190214Srpaulo#include <sys/bufmod.h> 53190214Srpaulo#endif 54190214Srpaulo#include <sys/dlpi.h> 55190214Srpaulo#include <sys/stream.h> 56190214Srpaulo 57190214Srpaulo#include <errno.h> 58190214Srpaulo#include <memory.h> 59190214Srpaulo#include <stdio.h> 60190214Srpaulo#include <stdlib.h> 61190214Srpaulo#include <string.h> 62190214Srpaulo#include <stropts.h> 63190214Srpaulo#include <unistd.h> 64190214Srpaulo 65276768Sdelphij#ifdef HAVE_LIBDLPI 66276768Sdelphij#include <libdlpi.h> 67276768Sdelphij#endif 68276768Sdelphij 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{ 82276768Sdelphij struct pcap_dlpi *pd = p->priv; 83190214Srpaulo 84190214Srpaulo /* 85190214Srpaulo * "ps_recv" counts packets handed to the filter, not packets 86190214Srpaulo * that passed the filter. As filtering is done in userland, 87190214Srpaulo * this would not include packets dropped because we ran out 88190214Srpaulo * of buffer space; in order to make this more like other 89190214Srpaulo * platforms (Linux 2.4 and later, BSDs with BPF), where the 90190214Srpaulo * "packets received" count includes packets received but dropped 91190214Srpaulo * due to running out of buffer space, and to keep from confusing 92190214Srpaulo * applications that, for example, compute packet drop percentages, 93190214Srpaulo * we also make it count packets dropped by "bufmod" (otherwise we 94190214Srpaulo * might run the risk of the packet drop count being bigger than 95190214Srpaulo * the received-packet count). 96190214Srpaulo * 97190214Srpaulo * "ps_drop" counts packets dropped by "bufmod" because of 98190214Srpaulo * flow control requirements or resource exhaustion; it doesn't 99190214Srpaulo * count packets dropped by the interface driver, or packets 100190214Srpaulo * dropped upstream. As filtering is done in userland, it counts 101190214Srpaulo * packets regardless of whether they would've passed the filter. 102190214Srpaulo * 103190214Srpaulo * These statistics don't include packets not yet read from 104190214Srpaulo * the kernel by libpcap, but they may include packets not 105190214Srpaulo * yet read from libpcap by the application. 106190214Srpaulo */ 107276768Sdelphij *ps = pd->stat; 108190214Srpaulo 109190214Srpaulo /* 110190214Srpaulo * Add in the drop count, as per the above comment. 111190214Srpaulo */ 112190214Srpaulo ps->ps_recv += ps->ps_drop; 113190214Srpaulo return (0); 114190214Srpaulo} 115190214Srpaulo 116190214Srpaulo/* 117190214Srpaulo * Loop through the packets and call the callback for each packet. 118190214Srpaulo * Return the number of packets read. 119190214Srpaulo */ 120190214Srpauloint 121190214Srpaulopcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, 122190214Srpaulo int count, u_char *bufp, int len) 123190214Srpaulo{ 124276768Sdelphij struct pcap_dlpi *pd = p->priv; 125190214Srpaulo int n, caplen, origlen; 126190214Srpaulo u_char *ep, *pk; 127190214Srpaulo struct pcap_pkthdr pkthdr; 128190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 129190214Srpaulo struct sb_hdr *sbp; 130190214Srpaulo#ifdef LBL_ALIGN 131190214Srpaulo struct sb_hdr sbhdr; 132190214Srpaulo#endif 133190214Srpaulo#endif 134190214Srpaulo 135190214Srpaulo /* Loop through packets */ 136190214Srpaulo ep = bufp + len; 137190214Srpaulo n = 0; 138190214Srpaulo 139190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 140190214Srpaulo while (bufp < ep) { 141190214Srpaulo /* 142190214Srpaulo * Has "pcap_breakloop()" been called? 143190214Srpaulo * If so, return immediately - if we haven't read any 144190214Srpaulo * packets, clear the flag and return -2 to indicate 145190214Srpaulo * that we were told to break out of the loop, otherwise 146190214Srpaulo * leave the flag set, so that the *next* call will break 147190214Srpaulo * out of the loop without having read any packets, and 148190214Srpaulo * return the number of packets we've processed so far. 149190214Srpaulo */ 150190214Srpaulo if (p->break_loop) { 151190214Srpaulo if (n == 0) { 152190214Srpaulo p->break_loop = 0; 153190214Srpaulo return (-2); 154190214Srpaulo } else { 155190214Srpaulo p->bp = bufp; 156190214Srpaulo p->cc = ep - bufp; 157190214Srpaulo return (n); 158190214Srpaulo } 159190214Srpaulo } 160190214Srpaulo#ifdef LBL_ALIGN 161190214Srpaulo if ((long)bufp & 3) { 162190214Srpaulo sbp = &sbhdr; 163190214Srpaulo memcpy(sbp, bufp, sizeof(*sbp)); 164190214Srpaulo } else 165190214Srpaulo#endif 166190214Srpaulo sbp = (struct sb_hdr *)bufp; 167276768Sdelphij pd->stat.ps_drop = sbp->sbh_drops; 168190214Srpaulo pk = bufp + sizeof(*sbp); 169190214Srpaulo bufp += sbp->sbh_totlen; 170190214Srpaulo origlen = sbp->sbh_origlen; 171190214Srpaulo caplen = sbp->sbh_msglen; 172190214Srpaulo#else 173190214Srpaulo origlen = len; 174190214Srpaulo caplen = min(p->snapshot, len); 175190214Srpaulo pk = bufp; 176190214Srpaulo bufp += caplen; 177190214Srpaulo#endif 178276768Sdelphij ++pd->stat.ps_recv; 179190214Srpaulo if (bpf_filter(p->fcode.bf_insns, pk, origlen, caplen)) { 180190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 181190214Srpaulo pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; 182190214Srpaulo pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; 183190214Srpaulo#else 184190214Srpaulo (void) gettimeofday(&pkthdr.ts, NULL); 185190214Srpaulo#endif 186190214Srpaulo pkthdr.len = origlen; 187190214Srpaulo pkthdr.caplen = caplen; 188190214Srpaulo /* Insure caplen does not exceed snapshot */ 189190214Srpaulo if (pkthdr.caplen > p->snapshot) 190190214Srpaulo pkthdr.caplen = p->snapshot; 191190214Srpaulo (*callback)(user, &pkthdr, pk); 192276768Sdelphij if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { 193190214Srpaulo p->cc = ep - bufp; 194190214Srpaulo p->bp = bufp; 195190214Srpaulo return (n); 196190214Srpaulo } 197190214Srpaulo } 198190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 199190214Srpaulo } 200190214Srpaulo#endif 201190214Srpaulo p->cc = 0; 202190214Srpaulo return (n); 203190214Srpaulo} 204190214Srpaulo 205190214Srpaulo/* 206190214Srpaulo * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. 207190214Srpaulo */ 208190214Srpauloint 209190214Srpaulopcap_process_mactype(pcap_t *p, u_int mactype) 210190214Srpaulo{ 211190214Srpaulo int retv = 0; 212190214Srpaulo 213190214Srpaulo switch (mactype) { 214190214Srpaulo 215190214Srpaulo case DL_CSMACD: 216190214Srpaulo case DL_ETHER: 217190214Srpaulo p->linktype = DLT_EN10MB; 218190214Srpaulo p->offset = 2; 219190214Srpaulo /* 220190214Srpaulo * This is (presumably) a real Ethernet capture; give it a 221190214Srpaulo * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 222190214Srpaulo * that an application can let you choose it, in case you're 223190214Srpaulo * capturing DOCSIS traffic that a Cisco Cable Modem 224190214Srpaulo * Termination System is putting out onto an Ethernet (it 225190214Srpaulo * doesn't put an Ethernet header onto the wire, it puts raw 226190214Srpaulo * DOCSIS frames out on the wire inside the low-level 227190214Srpaulo * Ethernet framing). 228190214Srpaulo */ 229190214Srpaulo p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); 230190214Srpaulo /* 231190214Srpaulo * If that fails, just leave the list empty. 232190214Srpaulo */ 233190214Srpaulo if (p->dlt_list != NULL) { 234190214Srpaulo p->dlt_list[0] = DLT_EN10MB; 235190214Srpaulo p->dlt_list[1] = DLT_DOCSIS; 236190214Srpaulo p->dlt_count = 2; 237190214Srpaulo } 238190214Srpaulo break; 239190214Srpaulo 240190214Srpaulo case DL_FDDI: 241190214Srpaulo p->linktype = DLT_FDDI; 242190214Srpaulo p->offset = 3; 243190214Srpaulo break; 244190214Srpaulo 245190214Srpaulo case DL_TPR: 246190214Srpaulo /* XXX - what about DL_TPB? Is that Token Bus? */ 247190214Srpaulo p->linktype = DLT_IEEE802; 248190214Srpaulo p->offset = 2; 249190214Srpaulo break; 250190214Srpaulo 251190214Srpaulo#ifdef HAVE_SOLARIS 252190214Srpaulo case DL_IPATM: 253190214Srpaulo p->linktype = DLT_SUNATM; 254190214Srpaulo p->offset = 0; /* works for LANE and LLC encapsulation */ 255190214Srpaulo break; 256190214Srpaulo#endif 257190214Srpaulo 258190214Srpaulo default: 259190214Srpaulo snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype %u", 260190214Srpaulo mactype); 261190214Srpaulo retv = -1; 262190214Srpaulo } 263190214Srpaulo 264190214Srpaulo return (retv); 265190214Srpaulo} 266190214Srpaulo 267190214Srpaulo#ifdef HAVE_SYS_BUFMOD_H 268190214Srpaulo/* 269190214Srpaulo * Push and configure the buffer module. Returns -1 for error, otherwise 0. 270190214Srpaulo */ 271190214Srpauloint 272276768Sdelphijpcap_conf_bufmod(pcap_t *p, int snaplen) 273190214Srpaulo{ 274276768Sdelphij struct timeval to; 275190214Srpaulo bpf_u_int32 ss, chunksize; 276190214Srpaulo 277190214Srpaulo /* Non-standard call to get the data nicely buffered. */ 278190214Srpaulo if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 279190214Srpaulo pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); 280276768Sdelphij return (-1); 281190214Srpaulo } 282190214Srpaulo 283190214Srpaulo ss = snaplen; 284190214Srpaulo if (ss > 0 && 285190214Srpaulo strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 286190214Srpaulo pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); 287276768Sdelphij return (-1); 288190214Srpaulo } 289190214Srpaulo 290276768Sdelphij if (p->opt.immediate) { 291276768Sdelphij /* Set the timeout to zero, for immediate delivery. */ 292276768Sdelphij to.tv_sec = 0; 293276768Sdelphij to.tv_usec = 0; 294190214Srpaulo if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 295190214Srpaulo pcap_stream_err("SBIOCSTIME", errno, p->errbuf); 296276768Sdelphij return (-1); 297190214Srpaulo } 298276768Sdelphij } else { 299276768Sdelphij /* Set up the bufmod timeout. */ 300276768Sdelphij if (p->opt.timeout != 0) { 301276768Sdelphij to.tv_sec = p->opt.timeout / 1000; 302276768Sdelphij to.tv_usec = (p->opt.timeout * 1000) % 1000000; 303276768Sdelphij if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 304276768Sdelphij pcap_stream_err("SBIOCSTIME", errno, p->errbuf); 305276768Sdelphij return (-1); 306276768Sdelphij } 307276768Sdelphij } 308190214Srpaulo 309276768Sdelphij /* Set the chunk length. */ 310276768Sdelphij chunksize = CHUNKSIZE; 311276768Sdelphij if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) 312276768Sdelphij != 0) { 313276768Sdelphij pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); 314276768Sdelphij return (-1); 315276768Sdelphij } 316190214Srpaulo } 317190214Srpaulo 318276768Sdelphij return (0); 319190214Srpaulo} 320190214Srpaulo#endif /* HAVE_SYS_BUFMOD_H */ 321190214Srpaulo 322190214Srpaulo/* 323190214Srpaulo * Allocate data buffer. Returns -1 if memory allocation fails, else 0. 324190214Srpaulo */ 325190214Srpauloint 326190214Srpaulopcap_alloc_databuf(pcap_t *p) 327190214Srpaulo{ 328190214Srpaulo p->bufsize = PKTBUFSIZE; 329190214Srpaulo p->buffer = (u_char *)malloc(p->bufsize + p->offset); 330190214Srpaulo if (p->buffer == NULL) { 331190214Srpaulo strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE); 332190214Srpaulo return (-1); 333190214Srpaulo } 334190214Srpaulo 335190214Srpaulo return (0); 336190214Srpaulo} 337190214Srpaulo 338190214Srpaulo/* 339190214Srpaulo * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise 340190214Srpaulo * length of returned data on success. 341190214Srpaulo */ 342190214Srpauloint 343190214Srpaulostrioctl(int fd, int cmd, int len, char *dp) 344190214Srpaulo{ 345190214Srpaulo struct strioctl str; 346190214Srpaulo int retv; 347190214Srpaulo 348190214Srpaulo str.ic_cmd = cmd; 349190214Srpaulo str.ic_timout = -1; 350190214Srpaulo str.ic_len = len; 351190214Srpaulo str.ic_dp = dp; 352190214Srpaulo if ((retv = ioctl(fd, I_STR, &str)) < 0) 353190214Srpaulo return (retv); 354190214Srpaulo 355190214Srpaulo return (str.ic_len); 356190214Srpaulo} 357190214Srpaulo 358214518Srpaulo#ifdef HAVE_SYS_BUFMOD_H 359190214Srpaulo/* 360190214Srpaulo * Write stream error message to errbuf. 361190214Srpaulo */ 362190214Srpaulostatic void 363190214Srpaulopcap_stream_err(const char *func, int err, char *errbuf) 364190214Srpaulo{ 365190214Srpaulo snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", func, pcap_strerror(err)); 366190214Srpaulo} 367214518Srpaulo#endif 368