1 /* 2 * This code is derived from code formerly in pcap-dlpi.c, originally 3 * contributed by Atanu Ghosh (atanu@cs.ucl.ac.uk), University College 4 * London, and subsequently modified by Guy Harris (guy@alum.mit.edu), 5 * Mark Pizzolato <List-tcpdump-workers@subscriptions.pizzolato.net>, 6 * Mark C. Brown (mbrown@hp.com), and Sagun Shakya <Sagun.Shakya@Sun.COM>. 7 */ 8 9 /* 10 * This file contains dlpi/libdlpi related common functions used 11 * by pcap-[dlpi,libdlpi].c. 12 */ 13 14 #include <config.h> 15 16 #ifndef DL_IPATM 17 #define DL_IPATM 0x12 /* ATM Classical IP interface */ 18 #endif 19 20 #ifdef HAVE_SYS_BUFMOD_H 21 /* 22 * Size of a bufmod chunk to pass upstream; that appears to be the 23 * biggest value to which you can set it, and setting it to that value 24 * (which is bigger than what appears to be the Solaris default of 8192) 25 * reduces the number of packet drops. 26 */ 27 #define CHUNKSIZE 65536 28 29 /* 30 * Size of the buffer to allocate for packet data we read; it must be 31 * large enough to hold a chunk. 32 */ 33 #define PKTBUFSIZE CHUNKSIZE 34 35 #else /* HAVE_SYS_BUFMOD_H */ 36 37 /* 38 * Size of the buffer to allocate for packet data we read; this is 39 * what the value used to be - there's no particular reason why it 40 * should be tied to MAXDLBUF, but we'll leave it as this for now. 41 */ 42 #define MAXDLBUF 8192 43 #define PKTBUFSIZE (MAXDLBUF * sizeof(bpf_u_int32)) 44 45 #endif 46 47 #include <sys/types.h> 48 #include <sys/time.h> 49 #ifdef HAVE_SYS_BUFMOD_H 50 #include <sys/bufmod.h> 51 #endif 52 #include <sys/dlpi.h> 53 #include <sys/stream.h> 54 55 #include <errno.h> 56 #include <memory.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <stropts.h> 61 #include <unistd.h> 62 63 #ifdef HAVE_LIBDLPI 64 #include <libdlpi.h> 65 #endif 66 67 #include "pcap-int.h" 68 #include "dlpisubs.h" 69 70 #ifdef HAVE_SYS_BUFMOD_H 71 static void pcap_stream_err(const char *, int, char *); 72 #endif 73 74 /* 75 * Get the packet statistics. 76 */ 77 int 78 pcap_stats_dlpi(pcap_t *p, struct pcap_stat *ps) 79 { 80 struct pcap_dlpi *pd = p->priv; 81 82 /* 83 * "ps_recv" counts packets handed to the filter, not packets 84 * that passed the filter. As filtering is done in userland, 85 * this would not include packets dropped because we ran out 86 * of buffer space; in order to make this more like other 87 * platforms (Linux 2.4 and later, BSDs with BPF), where the 88 * "packets received" count includes packets received but dropped 89 * due to running out of buffer space, and to keep from confusing 90 * applications that, for example, compute packet drop percentages, 91 * we also make it count packets dropped by "bufmod" (otherwise we 92 * might run the risk of the packet drop count being bigger than 93 * the received-packet count). 94 * 95 * "ps_drop" counts packets dropped by "bufmod" because of 96 * flow control requirements or resource exhaustion; it doesn't 97 * count packets dropped by the interface driver, or packets 98 * dropped upstream. As filtering is done in userland, it counts 99 * packets regardless of whether they would've passed the filter. 100 * 101 * These statistics don't include packets not yet read from 102 * the kernel by libpcap, but they may include packets not 103 * yet read from libpcap by the application. 104 */ 105 *ps = pd->stat; 106 107 /* 108 * Add in the drop count, as per the above comment. 109 */ 110 ps->ps_recv += ps->ps_drop; 111 return (0); 112 } 113 114 /* 115 * Does the processor for which we're compiling this support aligned loads? 116 */ 117 #if (defined(__i386__) || defined(_M_IX86) || defined(__X86__) || defined(__x86_64__) || defined(_M_X64)) || \ 118 (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__)) || \ 119 (defined(__m68k__) && (!defined(__mc68000__) && !defined(__mc68010__))) || \ 120 (defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PPC64)) || \ 121 (defined(__s390__) || defined(__s390x__) || defined(__zarch__)) 122 /* Yes, it does. */ 123 #else 124 /* No, it doesn't. */ 125 #define REQUIRE_ALIGNMENT 126 #endif 127 128 /* 129 * Loop through the packets and call the callback for each packet. 130 * Return the number of packets read. 131 */ 132 int 133 pcap_process_pkts(pcap_t *p, pcap_handler callback, u_char *user, 134 int count, u_char *bufp, int len) 135 { 136 struct pcap_dlpi *pd = p->priv; 137 int n, caplen, origlen; 138 u_char *ep, *pk; 139 struct pcap_pkthdr pkthdr; 140 #ifdef HAVE_SYS_BUFMOD_H 141 struct sb_hdr *sbp; 142 #ifdef REQUIRE_ALIGNMENT 143 struct sb_hdr sbhdr; 144 #endif 145 #endif 146 147 /* 148 * Loop through packets. 149 * 150 * This assumes that a single buffer of packets will have 151 * <= INT_MAX packets, so the packet count doesn't overflow. 152 */ 153 ep = bufp + len; 154 n = 0; 155 156 #ifdef HAVE_SYS_BUFMOD_H 157 while (bufp < ep) { 158 /* 159 * Has "pcap_breakloop()" been called? 160 * If so, return immediately - if we haven't read any 161 * packets, clear the flag and return -2 to indicate 162 * that we were told to break out of the loop, otherwise 163 * leave the flag set, so that the *next* call will break 164 * out of the loop without having read any packets, and 165 * return the number of packets we've processed so far. 166 */ 167 if (p->break_loop) { 168 if (n == 0) { 169 p->break_loop = 0; 170 return (-2); 171 } else { 172 p->bp = bufp; 173 p->cc = ep - bufp; 174 return (n); 175 } 176 } 177 #ifdef REQUIRE_ALIGNMENT 178 if ((long)bufp & 3) { 179 sbp = &sbhdr; 180 memcpy(sbp, bufp, sizeof(*sbp)); 181 } else 182 #endif 183 sbp = (struct sb_hdr *)bufp; 184 pd->stat.ps_drop = sbp->sbh_drops; 185 pk = bufp + sizeof(*sbp); 186 bufp += sbp->sbh_totlen; 187 origlen = sbp->sbh_origlen; 188 caplen = sbp->sbh_msglen; 189 #else 190 origlen = len; 191 caplen = min(p->snapshot, len); 192 pk = bufp; 193 bufp += caplen; 194 #endif 195 ++pd->stat.ps_recv; 196 if (pcapint_filter(p->fcode.bf_insns, pk, origlen, caplen)) { 197 #ifdef HAVE_SYS_BUFMOD_H 198 pkthdr.ts.tv_sec = sbp->sbh_timestamp.tv_sec; 199 pkthdr.ts.tv_usec = sbp->sbh_timestamp.tv_usec; 200 #else 201 (void) gettimeofday(&pkthdr.ts, NULL); 202 #endif 203 pkthdr.len = origlen; 204 pkthdr.caplen = caplen; 205 /* Insure caplen does not exceed snapshot */ 206 if (pkthdr.caplen > (bpf_u_int32)p->snapshot) 207 pkthdr.caplen = (bpf_u_int32)p->snapshot; 208 (*callback)(user, &pkthdr, pk); 209 if (++n >= count && !PACKET_COUNT_IS_UNLIMITED(count)) { 210 p->cc = ep - bufp; 211 p->bp = bufp; 212 return (n); 213 } 214 } 215 #ifdef HAVE_SYS_BUFMOD_H 216 } 217 #endif 218 p->cc = 0; 219 return (n); 220 } 221 222 /* 223 * Process the mac type. Returns -1 if no matching mac type found, otherwise 0. 224 */ 225 int 226 pcap_process_mactype(pcap_t *p, u_int mactype) 227 { 228 int retv = 0; 229 230 switch (mactype) { 231 232 case DL_CSMACD: 233 case DL_ETHER: 234 p->linktype = DLT_EN10MB; 235 p->offset = 2; 236 /* 237 * This is (presumably) a real Ethernet capture; give it a 238 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so 239 * that an application can let you choose it, in case you're 240 * capturing DOCSIS traffic that a Cisco Cable Modem 241 * Termination System is putting out onto an Ethernet (it 242 * doesn't put an Ethernet header onto the wire, it puts raw 243 * DOCSIS frames out on the wire inside the low-level 244 * Ethernet framing). 245 */ 246 p->dlt_list = (u_int *)malloc(sizeof(u_int) * 2); 247 if (p->dlt_list == NULL) { 248 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 249 errno, "malloc"); 250 return (-1); 251 } 252 p->dlt_list[0] = DLT_EN10MB; 253 p->dlt_list[1] = DLT_DOCSIS; 254 p->dlt_count = 2; 255 break; 256 257 case DL_FDDI: 258 p->linktype = DLT_FDDI; 259 p->offset = 3; 260 break; 261 262 case DL_TPR: 263 /* XXX - what about DL_TPB? Is that Token Bus? */ 264 p->linktype = DLT_IEEE802; 265 p->offset = 2; 266 break; 267 268 #ifdef HAVE_SOLARIS 269 case DL_IPATM: 270 p->linktype = DLT_SUNATM; 271 p->offset = 0; /* works for LANE and LLC encapsulation */ 272 break; 273 #endif 274 275 #ifdef DL_IPV4 276 case DL_IPV4: 277 p->linktype = DLT_IPV4; 278 p->offset = 0; 279 break; 280 #endif 281 282 #ifdef DL_IPV6 283 case DL_IPV6: 284 p->linktype = DLT_IPV6; 285 p->offset = 0; 286 break; 287 #endif 288 289 #ifdef DL_IPNET 290 case DL_IPNET: 291 /* 292 * XXX - DL_IPNET devices default to "raw IP" rather than 293 * "IPNET header"; see 294 * 295 * https://seclists.org/tcpdump/2009/q1/202 296 * 297 * We'd have to do DL_IOC_IPNET_INFO to enable getting 298 * the IPNET header. 299 */ 300 p->linktype = DLT_RAW; 301 p->offset = 0; 302 break; 303 #endif 304 305 default: 306 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "unknown mactype 0x%x", 307 mactype); 308 retv = -1; 309 } 310 311 return (retv); 312 } 313 314 #ifdef HAVE_SYS_BUFMOD_H 315 /* 316 * Push and configure the buffer module. Returns -1 for error, otherwise 0. 317 */ 318 int 319 pcap_conf_bufmod(pcap_t *p, int snaplen) 320 { 321 struct timeval to; 322 bpf_u_int32 ss, chunksize; 323 324 /* Non-standard call to get the data nicely buffered. */ 325 if (ioctl(p->fd, I_PUSH, "bufmod") != 0) { 326 pcap_stream_err("I_PUSH bufmod", errno, p->errbuf); 327 return (-1); 328 } 329 330 ss = snaplen; 331 if (ss > 0 && 332 strioctl(p->fd, SBIOCSSNAP, sizeof(ss), (char *)&ss) != 0) { 333 pcap_stream_err("SBIOCSSNAP", errno, p->errbuf); 334 return (-1); 335 } 336 337 if (p->opt.immediate) { 338 /* Set the timeout to zero, for immediate delivery. */ 339 to.tv_sec = 0; 340 to.tv_usec = 0; 341 if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 342 pcap_stream_err("SBIOCSTIME", errno, p->errbuf); 343 return (-1); 344 } 345 } else { 346 /* Set up the bufmod timeout. */ 347 if (p->opt.timeout != 0) { 348 to.tv_sec = p->opt.timeout / 1000; 349 to.tv_usec = (p->opt.timeout * 1000) % 1000000; 350 if (strioctl(p->fd, SBIOCSTIME, sizeof(to), (char *)&to) != 0) { 351 pcap_stream_err("SBIOCSTIME", errno, p->errbuf); 352 return (-1); 353 } 354 } 355 356 /* Set the chunk length. */ 357 chunksize = CHUNKSIZE; 358 if (strioctl(p->fd, SBIOCSCHUNK, sizeof(chunksize), (char *)&chunksize) 359 != 0) { 360 pcap_stream_err("SBIOCSCHUNKP", errno, p->errbuf); 361 return (-1); 362 } 363 } 364 365 return (0); 366 } 367 #endif /* HAVE_SYS_BUFMOD_H */ 368 369 /* 370 * Allocate data buffer. Returns -1 if memory allocation fails, else 0. 371 */ 372 int 373 pcap_alloc_databuf(pcap_t *p) 374 { 375 p->bufsize = PKTBUFSIZE; 376 p->buffer = malloc(p->bufsize + p->offset); 377 if (p->buffer == NULL) { 378 pcapint_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE, 379 errno, "malloc"); 380 return (-1); 381 } 382 383 return (0); 384 } 385 386 /* 387 * Issue a STREAMS I_STR ioctl. Returns -1 on error, otherwise 388 * length of returned data on success. 389 */ 390 int 391 strioctl(int fd, int cmd, int len, char *dp) 392 { 393 struct strioctl str; 394 int retv; 395 396 str.ic_cmd = cmd; 397 str.ic_timout = -1; 398 str.ic_len = len; 399 str.ic_dp = dp; 400 if ((retv = ioctl(fd, I_STR, &str)) < 0) 401 return (retv); 402 403 return (str.ic_len); 404 } 405 406 #ifdef HAVE_SYS_BUFMOD_H 407 /* 408 * Write stream error message to errbuf. 409 */ 410 static void 411 pcap_stream_err(const char *func, int err, char *errbuf) 412 { 413 pcapint_fmt_errmsg_for_errno(errbuf, PCAP_ERRBUF_SIZE, err, "%s", func); 414 } 415 #endif 416