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.62 2008-04-14 20:40:58 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 /*
     75  * Private data for capturing on NIT devices.
     76  */
     77 struct pcap_nit {
     78 	struct pcap_stat stat;
     79 };
     80 
     81 static int
     82 pcap_stats_nit(pcap_t *p, struct pcap_stat *ps)
     83 {
     84 	struct pcap_nit *pn = p->priv;
     85 
     86 	/*
     87 	 * "ps_recv" counts packets handed to the filter, not packets
     88 	 * that passed the filter.  As filtering is done in userland,
     89 	 * this does not include packets dropped because we ran out
     90 	 * of buffer space.
     91 	 *
     92 	 * "ps_drop" presumably counts packets dropped by the socket
     93 	 * because of flow control requirements or resource exhaustion;
     94 	 * it doesn't count packets dropped by the interface driver.
     95 	 * As filtering is done in userland, it counts packets regardless
     96 	 * of whether they would've passed the filter.
     97 	 *
     98 	 * These statistics don't include packets not yet read from the
     99 	 * kernel by libpcap or packets not yet read from libpcap by the
    100 	 * application.
    101 	 */
    102 	*ps = pn->stat;
    103 	return (0);
    104 }
    105 
    106 static int
    107 pcap_read_nit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
    108 {
    109 	struct pcap_nit *pn = p->priv;
    110 	register int cc, n;
    111 	register u_char *bp, *cp, *ep;
    112 	register struct nit_hdr *nh;
    113 	register int caplen;
    114 
    115 	cc = p->cc;
    116 	if (cc == 0) {
    117 		cc = read(p->fd, (char *)p->buffer, p->bufsize);
    118 		if (cc < 0) {
    119 			if (errno == EWOULDBLOCK)
    120 				return (0);
    121 			snprintf(p->errbuf, sizeof(p->errbuf), "pcap_read: %s",
    122 				pcap_strerror(errno));
    123 			return (-1);
    124 		}
    125 		bp = p->buffer;
    126 	} else
    127 		bp = p->bp;
    128 
    129 	/*
    130 	 * Loop through each packet.  The increment expression
    131 	 * rounds up to the next int boundary past the end of
    132 	 * the previous packet.
    133 	 */
    134 	n = 0;
    135 	ep = bp + cc;
    136 	while (bp < ep) {
    137 		/*
    138 		 * Has "pcap_breakloop()" been called?
    139 		 * If so, return immediately - if we haven't read any
    140 		 * packets, clear the flag and return -2 to indicate
    141 		 * that we were told to break out of the loop, otherwise
    142 		 * leave the flag set, so that the *next* call will break
    143 		 * out of the loop without having read any packets, and
    144 		 * return the number of packets we've processed so far.
    145 		 */
    146 		if (p->break_loop) {
    147 			if (n == 0) {
    148 				p->break_loop = 0;
    149 				return (-2);
    150 			} else {
    151 				p->cc = ep - bp;
    152 				p->bp = bp;
    153 				return (n);
    154 			}
    155 		}
    156 
    157 		nh = (struct nit_hdr *)bp;
    158 		cp = bp + sizeof(*nh);
    159 
    160 		switch (nh->nh_state) {
    161 
    162 		case NIT_CATCH:
    163 			break;
    164 
    165 		case NIT_NOMBUF:
    166 		case NIT_NOCLUSTER:
    167 		case NIT_NOSPACE:
    168 			pn->stat.ps_drop = nh->nh_dropped;
    169 			continue;
    170 
    171 		case NIT_SEQNO:
    172 			continue;
    173 
    174 		default:
    175 			snprintf(p->errbuf, sizeof(p->errbuf),
    176 			    "bad nit state %d", nh->nh_state);
    177 			return (-1);
    178 		}
    179 		++pn->stat.ps_recv;
    180 		bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
    181 		    sizeof(int) - 1) & ~(sizeof(int) - 1));
    182 
    183 		caplen = nh->nh_wirelen;
    184 		if (caplen > p->snapshot)
    185 			caplen = p->snapshot;
    186 		if (bpf_filter(p->fcode.bf_insns, cp, nh->nh_wirelen, caplen)) {
    187 			struct pcap_pkthdr h;
    188 			h.ts = nh->nh_timestamp;
    189 			h.len = nh->nh_wirelen;
    190 			h.caplen = caplen;
    191 			(*callback)(user, &h, cp);
    192 			if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
    193 				p->cc = ep - bp;
    194 				p->bp = bp;
    195 				return (n);
    196 			}
    197 		}
    198 	}
    199 	p->cc = 0;
    200 	return (n);
    201 }
    202 
    203 static int
    204 pcap_inject_nit(pcap_t *p, const void *buf, size_t size)
    205 {
    206 	struct sockaddr sa;
    207 	int ret;
    208 
    209 	memset(&sa, 0, sizeof(sa));
    210 	strncpy(sa.sa_data, device, sizeof(sa.sa_data));
    211 	ret = sendto(p->fd, buf, size, 0, &sa, sizeof(sa));
    212 	if (ret == -1) {
    213 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send: %s",
    214 		    pcap_strerror(errno));
    215 		return (-1);
    216 	}
    217 	return (ret);
    218 }
    219 
    220 static int
    221 nit_setflags(pcap_t *p)
    222 {
    223 	struct nit_ioc nioc;
    224 
    225 	memset(&nioc, 0, sizeof(nioc));
    226 	nioc.nioc_typetomatch = NT_ALLTYPES;
    227 	nioc.nioc_snaplen = p->snapshot;
    228 	nioc.nioc_bufalign = sizeof(int);
    229 	nioc.nioc_bufoffset = 0;
    230 
    231 	if (p->opt.buffer_size != 0)
    232 		nioc.nioc_bufspace = p->opt.buffer_size;
    233 	else {
    234 		/* Default buffer size */
    235 		nioc.nioc_bufspace = BUFSPACE;
    236 	}
    237 
    238 	if (p->opt.immediate) {
    239 		/*
    240 		 * XXX - will this cause packets to be delivered immediately?
    241 		 * XXX - given that this is for SunOS prior to 4.0, do
    242 		 * we care?
    243 		 */
    244 		nioc.nioc_chunksize = 0;
    245 	} else
    246 		nioc.nioc_chunksize = CHUNKSIZE;
    247 	if (p->opt.timeout != 0) {
    248 		nioc.nioc_flags |= NF_TIMEOUT;
    249 		nioc.nioc_timeout.tv_sec = p->opt.timeout / 1000;
    250 		nioc.nioc_timeout.tv_usec = (p->opt.timeout * 1000) % 1000000;
    251 	}
    252 	if (p->opt.promisc)
    253 		nioc.nioc_flags |= NF_PROMISC;
    254 
    255 	if (ioctl(p->fd, SIOCSNIT, &nioc) < 0) {
    256 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "SIOCSNIT: %s",
    257 		    pcap_strerror(errno));
    258 		return (-1);
    259 	}
    260 	return (0);
    261 }
    262 
    263 static int
    264 pcap_activate_nit(pcap_t *p)
    265 {
    266 	int fd;
    267 	struct sockaddr_nit snit;
    268 
    269 	if (p->opt.rfmon) {
    270 		/*
    271 		 * No monitor mode on SunOS 3.x or earlier (no
    272 		 * Wi-Fi *devices* for the hardware that supported
    273 		 * them!).
    274 		 */
    275 		return (PCAP_ERROR_RFMON_NOTSUP);
    276 	}
    277 
    278 	if (p->snapshot < 96)
    279 		/*
    280 		 * NIT requires a snapshot length of at least 96.
    281 		 */
    282 		p->snapshot = 96;
    283 
    284 	memset(p, 0, sizeof(*p));
    285 	p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
    286 	if (fd < 0) {
    287 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    288 		    "socket: %s", pcap_strerror(errno));
    289 		goto bad;
    290 	}
    291 	snit.snit_family = AF_NIT;
    292 	(void)strncpy(snit.snit_ifname, p->opt.source, NITIFSIZ);
    293 
    294 	if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
    295 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
    296 		    "bind: %s: %s", snit.snit_ifname, pcap_strerror(errno));
    297 		goto bad;
    298 	}
    299 	if (nit_setflags(p) < 0)
    300 		goto bad;
    301 
    302 	/*
    303 	 * NIT supports only ethernets.
    304 	 */
    305 	p->linktype = DLT_EN10MB;
    306 
    307 	p->bufsize = BUFSPACE;
    308 	p->buffer = (u_char *)malloc(p->bufsize);
    309 	if (p->buffer == NULL) {
    310 		strlcpy(p->errbuf, pcap_strerror(errno), PCAP_ERRBUF_SIZE);
    311 		goto bad;
    312 	}
    313 
    314 	/*
    315 	 * "p->fd" is a socket, so "select()" should work on it.
    316 	 */
    317 	p->selectable_fd = p->fd;
    318 
    319 	/*
    320 	 * This is (presumably) a real Ethernet capture; give it a
    321 	 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
    322 	 * that an application can let you choose it, in case you're
    323 	 * capturing DOCSIS traffic that a Cisco Cable Modem
    324 	 * Termination System is putting out onto an Ethernet (it
    325 	 * doesn't put an Ethernet header onto the wire, it puts raw
    326 	 * DOCSIS frames out on the wire inside the low-level
    327 	 * Ethernet framing).
    328 	 */
    329 	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
    330 	/*
    331 	 * If that fails, just leave the list empty.
    332 	 */
    333 	if (p->dlt_list != NULL) {
    334 		p->dlt_list[0] = DLT_EN10MB;
    335 		p->dlt_list[1] = DLT_DOCSIS;
    336 		p->dlt_count = 2;
    337 	}
    338 
    339 	p->read_op = pcap_read_nit;
    340 	p->inject_op = pcap_inject_nit;
    341 	p->setfilter_op = install_bpf_program;	/* no kernel filtering */
    342 	p->setdirection_op = NULL;	/* Not implemented. */
    343 	p->set_datalink_op = NULL;	/* can't change data link type */
    344 	p->getnonblock_op = pcap_getnonblock_fd;
    345 	p->setnonblock_op = pcap_setnonblock_fd;
    346 	p->stats_op = pcap_stats_nit;
    347 
    348 	return (0);
    349  bad:
    350 	pcap_cleanup_live_common(p);
    351 	return (PCAP_ERROR);
    352 }
    353 
    354 pcap_t *
    355 pcap_create_interface(const char *device, char *ebuf)
    356 {
    357 	pcap_t *p;
    358 
    359 	p = pcap_create_common(device, ebuf, sizeof (struct pcap_nit));
    360 	if (p == NULL)
    361 		return (NULL);
    362 
    363 	p->activate_op = pcap_activate_nit;
    364 	return (p);
    365 }
    366 
    367 int
    368 pcap_platform_finddevs(pcap_if_t **alldevsp, char *errbuf)
    369 {
    370 	return (0);
    371 }
    372