Home | History | Annotate | Download | only in libpcap
      1 /*
      2  * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 #ifndef lint
     22 static const char rcsid[] _U_ =
     23     "@(#) $Header: /tcpdump/master/libpcap/pcap-nit.c,v 1.57.2.1 2005/05/03 18:54:37 guy Exp $ (LBL)";
     24 #endif
     25 
     26 #ifdef HAVE_CONFIG_H
     27 #include "config.h"
     28 #endif
     29 
     30 #include <sys/types.h>
     31 #include <sys/time.h>
     32 #include <sys/timeb.h>
     33 #include <sys/file.h>
     34 #include <sys/ioctl.h>
     35 #include <sys/socket.h>
     36 
     37 #include <net/if.h>
     38 #include <net/nit.h>
     39 
     40 #include <netinet/in.h>
     41 #include <netinet/in_systm.h>
     42 #include <netinet/ip.h>
     43 #include <netinet/if_ether.h>
     44 #include <netinet/ip_var.h>
     45 #include <netinet/udp.h>
     46 #include <netinet/udp_var.h>
     47 #include <netinet/tcp.h>
     48 #include <netinet/tcpip.h>
     49 
     50 #include <ctype.h>
     51 #include <errno.h>
     52 #include <stdio.h>
     53 
     54 #include "pcap-int.h"
     55 
     56 #ifdef HAVE_OS_PROTO_H
     57 #include "os-proto.h"
     58 #endif
     59 
     60 /*
     61  * The chunk size for NIT.  This is the amount of buffering
     62  * done for read calls.
     63  */
     64 #define CHUNKSIZE (2*1024)
     65 
     66 /*
     67  * The total buffer space used by NIT.
     68  */
     69 #define BUFSPACE (4*CHUNKSIZE)
     70 
     71 /* Forwards */
     72 static int nit_setflags(int, int, int, char *);
     73 
     74 static int
     75 pcap_stats_nit(pcap_t *p, struct pcap_stat *ps)
     76 {
     77 
     78 	/*
     79 	 * "ps_recv" counts packets handed to the filter, not packets
     80 	 * that passed the filter.  As filtering is done in userland,
     81 	 * this does not include packets dropped because we ran out
     82 	 * of buffer space.
     83 	 *
     84 	 * "ps_drop" presumably counts packets dropped by the socket
     85 	 * because of flow control requirements or resource exhaustion;
     86 	 * it doesn't count packets dropped by the interface driver.
     87 	 * As filtering is done in userland, it counts packets regardless
     88 	 * of whether they would've passed the filter.
     89 	 *
     90 	 * These statistics don't include packets not yet read from the
     91 	 * kernel by libpcap or packets not yet read from libpcap by the
     92 	 * application.
     93 	 */
     94 	*ps = p->md.stat;
     95 	return (0);
     96 }
     97 
     98 static int
     99 pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
    100 {
    101 	register int cc, n;
    102 	register struct bpf_insn *fcode = p->fcode.bf_insns;
    103 	register u_char *bp, *cp, *ep;
    104 	register struct nit_hdr *nh;
    105 	register int caplen;
    106 
    107 	cc = p->cc;
    108 	if (cc == 0) {
    109 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
    110 		if (cc < 0) {
    111 			if (errno == EWOULDBLOCK)
    112 				return (0);
    113 			snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s",
    114 				pcap_strerror(errno));
    115 			return (-1);
    116 		}
    117 		bp = p->buffer;
    118 	} else
    119 		bp = p->bp;
    120 
    121 	/*
    122 	 * Loop through each packet.  The increment expression
    123 	 * rounds up to the next int boundary past the end of
    124 	 * the previous packet.
    125 	 */
    126 	n = 0;
    127 	ep = bp + cc;
    128 	while (bp < ep) {
    129 		/*
    130 		 * Has "pcap_breakloop()" been called?
    131 		 * If so, return immediately - if we haven't read any
    132 		 * packets, clear the flag and return -2 to indicate
    133 		 * that we were told to break out of the loop, otherwise
    134 		 * leave the flag set, so that the *next* call will break
    135 		 * out of the loop without having read any packets, and
    136 		 * return the number of packets we've processed so far.
    137 		 */
    138 		if (p->break_loop) {
    139 			if (n == 0) {
    140 				p->break_loop = 0;
    141 				return (-2);
    142 			} else {
    143 				p->cc = ep - bp;
    144 				p->bp = bp;
    145 				return (n);
    146 			}
    147 		}
    148 
    149 		nh = (struct nit_hdr *)bp;
    150 		cp = bp + sizeof(*nh);
    151 
    152 		switch (nh->nh_state) {
    153 
    154 		case NIT_CATCH:
    155 			break;
    156 
    157 		case NIT_NOMBUF:
    158 		case NIT_NOCLUSTER:
    159 		case NIT_NOSPACE:
    160 			p->md.stat.ps_drop = nh->nh_dropped;
    161 			continue;
    162 
    163 		case NIT_SEQNO:
    164 			continue;
    165 
    166 		default:
    167 			snprintf(p->errbuf, sizeof(p->errbuf),
    168 			    "bad nit state %d", nh->nh_state);
    169 			return (-1);
    170 		}
    171 		++p->md.stat.ps_recv;
    172 		bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
    173 		    sizeof(int) - 1) & ~(sizeof(int) - 1));
    174 
    175 		caplen = nh->nh_wirelen;
    176 		if (caplen > p->snapshot)
    177 			caplen = p->snapshot;
    178 		if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) {
    179 			struct pcap_pkthdr h;
    180 			h.ts = nh->nh_timestamp;
    181 			h.len = nh->nh_wirelen;
    182 			h.caplen = caplen;
    183 			(*callback)(user, &h, cp);
    184 			if (++n >= cnt && cnt >= 0) {
    185 				p->cc = ep - bp;
    186 				p->bp = bp;
    187 				return (n);
    188 			}
    189 		}
    190 	}
    191 	p->cc = 0;
    192 	return (n);
    193 }
    194 
    195 static int
    196 pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
    197 {
    198 	struct sockaddr sa;
    199 	int ret;
    200 
    201 	memset(&sa, 0, sizeof(sa));
    202 	strncpy(sa.sa_data, device, sizeof(sa.sa_data));
    203 	ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
    204 	if (ret == -1) {
    205 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
    206 		    pcap_strerror(errno));
    207 		return (-1);
    208 	}
    209 	return (ret);
    210 }
    211 
    212 static int
    213 nit_setflags(int fd, int promisc, int to_ms, char *ebuf)
    214 {
    215 	struct nit_ioc nioc;
    216 
    217 	memset(&nioc, 0, sizeof(nioc));
    218 	nioc.nioc_bufspace = BUFSPACE;
    219 	nioc.nioc_chunksize = CHUNKSIZE;
    220 	nioc.nioc_typetomatch = NT_ALLTYPES;
    221 	nioc.nioc_snaplen = p->snapshot;
    222 	nioc.nioc_bufalign = sizeof(int);
    223 	nioc.nioc_bufoffset = 0;
    224 
    225 	if (to_ms != 0) {
    226 		nioc.nioc_flags |= NF_TIMEOUT;
    227 		nioc.nioc_timeout.tv_sec = to_ms / 1000;
    228 		nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000;
    229 	}
    230 	if (promisc)
    231 		nioc.nioc_flags |= NF_PROMISC;
    232 
    233 	if (ioctl(fd, SIOCSNIT, &nioc) < 0) {
    234 		snprintf(ebuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s",
    235 		    pcap_strerror(errno));
    236 		return (-1);
    237 	}
    238 	return (0);
    239 }
    240 
    241 static void
    242 pcap_close_nit(pcap_t *p)
    243 {
    244 	pcap_close_common(p);
    245 	if (p->device != NULL)
    246 		free(p->device);
    247 }
    248 
    249 pcap_t *
    250 pcap_open_live(const char *device, int snaplen, int promisc, int to_ms,
    251     char *ebuf)
    252 {
    253 	int fd;
    254 	struct sockaddr_nit snit;
    255 	register pcap_t *p;
    256 
    257 	p = (pcap_t *)malloc(sizeof(*p));
    258 	if (p == NULL) {
    259 		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
    260 		return (NULL);
    261 	}
    262 
    263 	if (snaplen < 96)
    264 		/*
    265 		 * NIT requires a snapshot length of at least 96.
    266 		 */
    267 		snaplen = 96;
    268 
    269 	memset(p, 0, sizeof(*p));
    270 	p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
    271 	if (fd < 0) {
    272 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
    273 		    "socket: %s", pcap_strerror(errno));
    274 		goto bad;
    275 	}
    276 	snit.snit_family = AF_NIT;
    277 	(void)strncpy(snit.snit_ifname, device, NITIFSIZ);
    278 
    279 	if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
    280 		snprintf(ebuf, PCAP_ERRBUF_SIZE,
    281 		    "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
    282 		goto bad;
    283 	}
    284 	p->snapshot = snaplen;
    285 	nit_setflags(p->fd, promisc, to_ms, ebuf);
    286 
    287 	/*
    288 	 * NIT supports only ethernets.
    289 	 */
    290 	p->linktype = DLT_EN10MB;
    291 
    292 	p->bufsize = BUFSPACE;
    293 	p->buffer = (u_char *)malloc(p->bufsize);
    294 	if (p->buffer == NULL) {
    295 		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
    296 		goto bad;
    297 	}
    298 
    299 	/*
    300 	 * We need the device name in order to send packets.
    301 	 */
    302 	p->device = strdup(device);
    303 	if (p->device == NULL) {
    304 		strlcpy(ebuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
    305 		free(p->buffer);
    306 		goto bad;
    307 	}
    308 
    309 	/*
    310 	 * "p->fd" is a socket, so "select()" should work on it.
    311 	 */
    312 	p->selectable_fd = p->fd;
    313 
    314 	/*
    315 	 * This is (presumably) a real Ethernet capture; give it a
    316 	 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
    317 	 * that an application can let you choose it, in case you're
    318 	 * capturing DOCSIS traffic that a Cisco Cable Modem
    319 	 * Termination System is putting out onto an Ethernet (it
    320 	 * doesn't put an Ethernet header onto the wire, it puts raw
    321 	 * DOCSIS frames out on the wire inside the low-level
    322 	 * Ethernet framing).
    323 	 */
    324 	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
    325 	/*
    326 	 * If that fails, just leave the list empty.
    327 	 */
    328 	if (p->dlt_list != NULL) {
    329 		p->dlt_list[0] = DLT_EN10MB;
    330 		p->dlt_list[1] = DLT_DOCSIS;
    331 		p->dlt_count = 2;
    332 	}
    333 
    334 	p->read_op = pcap_read_nit;
    335 	p->inject_op = pcap_inject_nit;
    336 	p->setfilter_op = install_bpf_program;	/* no kernel filtering */
    337 	p->setdirection_op = NULL;	/* Not implemented. */
    338 	p->set_datalink_op = NULL;	/* can't change data link type */
    339 	p->getnonblock_op = pcap_getnonblock_fd;
    340 	p->setnonblock_op = pcap_setnonblock_fd;
    341 	p->stats_op = pcap_stats_nit;
    342 	p->close_op = pcap_close_nit;
    343 
    344 	return (p);
    345  bad:
    346 	if (fd >= 0)
    347 		close(fd);
    348 	free(p);
    349 	return (NULL);
    350 }
    351 
    352 int
    353 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
    354 {
    355 	return (0);
    356 }
    357