pcap-nit.c revision 17683
1193323Sed/*
2193323Sed * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that: (1) source code distributions
7193323Sed * retain the above copyright notice and this paragraph in its entirety, (2)
8193323Sed * distributions including binary code include the above copyright notice and
9193323Sed * this paragraph in its entirety in the documentation or other materials
10193323Sed * provided with the distribution, and (3) all advertising materials mentioning
11193323Sed * features or use of this software display the following acknowledgement:
12193323Sed * ``This product includes software developed by the University of California,
13193323Sed * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14193323Sed * the University nor the names of its contributors may be used to endorse
15193323Sed * or promote products derived from this software without specific prior
16193323Sed * written permission.
17193323Sed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18193323Sed * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19193323Sed * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20193323Sed */
21193323Sed#ifndef lint
22198892Srdivackystatic  char rcsid[] =
23198892Srdivacky    "@(#)$Header: pcap-nit.c,v 1.29 96/07/15 00:48:51 leres Exp $ (LBL)";
24198892Srdivacky#endif
25198090Srdivacky
26198090Srdivacky#include <sys/types.h>
27193323Sed#include <sys/time.h>
28193323Sed#include <sys/timeb.h>
29193323Sed#include <sys/file.h>
30193323Sed#include <sys/ioctl.h>
31193323Sed#include <sys/socket.h>
32198090Srdivacky
33193323Sed#include <net/if.h>
34193323Sed#include <net/nit.h>
35193323Sed
36193323Sed#include <netinet/in.h>
37198090Srdivacky#include <netinet/in_systm.h>
38193323Sed#include <netinet/ip.h>
39193323Sed#include <netinet/if_ether.h>
40193323Sed#include <netinet/ip_var.h>
41193323Sed#include <netinet/udp.h>
42198090Srdivacky#include <netinet/udp_var.h>
43198892Srdivacky#include <netinet/tcp.h>
44193323Sed#include <netinet/tcpip.h>
45198090Srdivacky
46198090Srdivacky#include <ctype.h>
47198892Srdivacky#include <errno.h>
48193323Sed#include <stdio.h>
49193323Sed
50198090Srdivacky#include "pcap-int.h"
51193323Sed
52193323Sed#include "gnuc.h"
53193323Sed#ifdef HAVE_OS_PROTO_H
54193323Sed#include "os-proto.h"
55198892Srdivacky#endif
56193323Sed
57198090Srdivacky/*
58198090Srdivacky * The chunk size for NIT.  This is the amount of buffering
59198090Srdivacky * done for read calls.
60193323Sed */
61198090Srdivacky#define CHUNKSIZE (2*1024)
62198090Srdivacky
63198090Srdivacky/*
64198892Srdivacky * The total buffer space used by NIT.
65193323Sed */
66198892Srdivacky#define BUFSPACE (4*CHUNKSIZE)
67198892Srdivacky
68198892Srdivacky/* Forwards */
69193323Sedstatic int nit_setflags(int, int, int, char *);
70193323Sed
71198090Srdivackyint
72193323Sedpcap_stats(pcap_t *p, struct pcap_stat *ps)
73193323Sed{
74198090Srdivacky
75198090Srdivacky	*ps = p->md.stat;
76198090Srdivacky	return (0);
77198090Srdivacky}
78198090Srdivacky
79198090Srdivackyint
80198090Srdivackypcap_read(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
81198090Srdivacky{
82198090Srdivacky	register int cc, n;
83198090Srdivacky	register struct bpf_insn *fcode = p->fcode.bf_insns;
84198892Srdivacky	register u_char *bp, *cp, *ep;
85198892Srdivacky	register struct nit_hdr *nh;
86193323Sed	register int caplen;
87198892Srdivacky
88198090Srdivacky	cc = p->cc;
89198396Srdivacky	if (cc == 0) {
90198090Srdivacky		cc = read(p->fd, (char *)p->buffer, p->bufsize);
91193323Sed		if (cc < 0) {
92193323Sed			if (errno == EWOULDBLOCK)
93198396Srdivacky				return (0);
94198396Srdivacky			sprintf(p->errbuf, "pcap_read: %s",
95193323Sed				pcap_strerror(errno));
96193323Sed			return (-1);
97198090Srdivacky		}
98198090Srdivacky		bp = p->buffer;
99193323Sed	} else
100193323Sed		bp = p->bp;
101193323Sed
102193323Sed	/*
103193323Sed	 * Loop through each packet.  The increment expression
104193323Sed	 * rounds up to the next int boundary past the end of
105193323Sed	 * the previous packet.
106193323Sed	 */
107193323Sed	n = 0;
108193323Sed	ep = bp + cc;
109193323Sed	while (bp < ep) {
110193323Sed		nh = (struct nit_hdr *)bp;
111193323Sed		cp = bp + sizeof(*nh);
112193323Sed
113193323Sed		switch (nh->nh_state) {
114198892Srdivacky
115193323Sed		case NIT_CATCH:
116193323Sed			break;
117193323Sed
118193323Sed		case NIT_NOMBUF:
119193323Sed		case NIT_NOCLUSTER:
120193323Sed		case NIT_NOSPACE:
121193323Sed			p->md.stat.ps_drop = nh->nh_dropped;
122193323Sed			continue;
123193323Sed
124193323Sed		case NIT_SEQNO:
125193323Sed			continue;
126193323Sed
127193323Sed		default:
128193323Sed			sprintf(p->errbuf, "bad nit state %d", nh->nh_state);
129193323Sed			return (-1);
130193323Sed		}
131198892Srdivacky		++p->md.stat.ps_recv;
132198892Srdivacky		bp += ((sizeof(struct nit_hdr) + nh->nh_datalen +
133198892Srdivacky		    sizeof(int) - 1) & ~(sizeof(int) - 1));
134198090Srdivacky
135198090Srdivacky		caplen = nh->nh_wirelen;
136198090Srdivacky		if (caplen > p->snapshot)
137198090Srdivacky			caplen = p->snapshot;
138198090Srdivacky		if (bpf_filter(fcode, cp, nh->nh_wirelen, caplen)) {
139193323Sed			struct pcap_pkthdr h;
140193323Sed			h.ts = nh->nh_timestamp;
141193323Sed			h.len = nh->nh_wirelen;
142193323Sed			h.caplen = caplen;
143193323Sed			(*callback)(user, &h, cp);
144193323Sed			if (++n >= cnt && cnt >= 0) {
145198090Srdivacky				p->cc = ep - bp;
146198892Srdivacky				p->bp = bp;
147198892Srdivacky				return (n);
148193323Sed			}
149198892Srdivacky		}
150193323Sed	}
151193323Sed	p->cc = 0;
152193323Sed	return (n);
153193323Sed}
154193323Sed
155193323Sedstatic int
156193323Sednit_setflags(int fd, int promisc, int to_ms, char *ebuf)
157193323Sed{
158193323Sed	struct nit_ioc nioc;
159193323Sed
160193323Sed	bzero((char *)&nioc, sizeof(nioc));
161193323Sed	nioc.nioc_bufspace = BUFSPACE;
162198090Srdivacky	nioc.nioc_chunksize = CHUNKSIZE;
163193323Sed	nioc.nioc_typetomatch = NT_ALLTYPES;
164193323Sed	nioc.nioc_snaplen = p->snapshot;
165193323Sed	nioc.nioc_bufalign = sizeof(int);
166193323Sed	nioc.nioc_bufoffset = 0;
167193323Sed
168193323Sed	if (to_ms != 0) {
169193323Sed		nioc.nioc_flags |= NF_TIMEOUT;
170193323Sed		nioc.nioc_timeout.tv_sec = to_ms / 1000;
171193323Sed		nioc.nioc_timeout.tv_usec = (to_ms * 1000) % 1000000;
172198892Srdivacky	}
173198892Srdivacky	if (promisc)
174198892Srdivacky		nioc.nioc_flags |= NF_PROMISC;
175198892Srdivacky
176198892Srdivacky	if (ioctl(fd, SIOCSNIT, &nioc) < 0) {
177193323Sed		sprintf(ebuf, "SIOCSNIT: %s", pcap_strerror(errno));
178198892Srdivacky		return (-1);
179198892Srdivacky	}
180198892Srdivacky	return (0);
181198892Srdivacky}
182198892Srdivacky
183198090Srdivackypcap_t *
184198090Srdivackypcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)
185198090Srdivacky{
186198090Srdivacky	int fd;
187198090Srdivacky	struct sockaddr_nit snit;
188198090Srdivacky	register pcap_t *p;
189193323Sed
190193323Sed	p = (pcap_t *)malloc(sizeof(*p));
191193323Sed	if (p == NULL) {
192193323Sed		strcpy(ebuf, pcap_strerror(errno));
193193323Sed		return (NULL);
194193323Sed	}
195193323Sed
196193323Sed	if (snaplen < 96)
197193323Sed		/*
198193323Sed		 * NIT requires a snapshot length of at least 96.
199193323Sed		 */
200193323Sed		snaplen = 96;
201193323Sed
202193323Sed	bzero(p, sizeof(*p));
203193323Sed	p->fd = fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
204193323Sed	if (fd < 0) {
205193323Sed		sprintf(ebuf, "socket: %s", pcap_strerror(errno));
206193323Sed		goto bad;
207193323Sed	}
208193323Sed	snit.snit_family = AF_NIT;
209193323Sed	(void)strncpy(snit.snit_ifname, device, NITIFSIZ);
210193323Sed
211193323Sed	if (bind(fd, (struct sockaddr *)&snit, sizeof(snit))) {
212193323Sed		sprintf(ebuf, "bind: %s: %s", snit.snit_ifname,
213193323Sed			pcap_strerror(errno));
214193323Sed		goto bad;
215198090Srdivacky	}
216193323Sed	p->snapshot = snaplen;
217198090Srdivacky	nit_setflags(p->fd, promisc, to_ms, ebuf);
218198396Srdivacky
219199481Srdivacky	/*
220198090Srdivacky	 * NIT supports only ethernets.
221198090Srdivacky	 */
222198396Srdivacky	p->linktype = DLT_EN10MB;
223198090Srdivacky
224198396Srdivacky	p->bufsize = BUFSPACE;
225198090Srdivacky	p->buffer = (u_char *)malloc(p->bufsize);
226199481Srdivacky	if (p->buffer == NULL) {
227198396Srdivacky		strcpy(ebuf, pcap_strerror(errno));
228198090Srdivacky		goto bad;
229198090Srdivacky	}
230198396Srdivacky	return (p);
231198396Srdivacky bad:
232198892Srdivacky	if (fd >= 0)
233198892Srdivacky		close(fd);
234198892Srdivacky	free(p);
235198396Srdivacky	return (NULL);
236198396Srdivacky}
237198090Srdivacky
238198090Srdivackyint
239193323Sedpcap_setfilter(pcap_t *p, struct bpf_program *fp)
240193323Sed{
241198090Srdivacky
242193323Sed	p->fcode = *fp;
243198090Srdivacky	return (0);
244198090Srdivacky}
245198892Srdivacky