• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   * Modifications made to accommodate the new SunOS4.0 NIT facility by
22   * Micky Liu, micky@cunixc.cc.columbia.edu, Columbia University in May, 1989.
23   * This module now handles the STREAMS based NIT.
24   */
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/dir.h>
34  #include <sys/fcntlcom.h>
35  #include <sys/file.h>
36  #include <sys/ioctl.h>
37  #include <sys/socket.h>
38  #include <sys/stropts.h>
39  
40  #include <net/if.h>
41  #include <net/nit.h>
42  #include <net/nit_if.h>
43  #include <net/nit_pf.h>
44  #include <net/nit_buf.h>
45  
46  #include <netinet/in.h>
47  #include <netinet/in_systm.h>
48  #include <netinet/ip.h>
49  #include <netinet/if_ether.h>
50  #include <netinet/ip_var.h>
51  #include <netinet/udp.h>
52  #include <netinet/udp_var.h>
53  #include <netinet/tcp.h>
54  #include <netinet/tcpip.h>
55  
56  #include <ctype.h>
57  #include <errno.h>
58  #include <stdio.h>
59  #include <string.h>
60  #include <unistd.h>
61  
62  #include "pcap-int.h"
63  
64  #ifdef HAVE_OS_PROTO_H
65  #include "os-proto.h"
66  #endif
67  
68  /*
69   * The chunk size for NIT.  This is the amount of buffering
70   * done for read calls.
71   */
72  #define CHUNKSIZE (2*1024)
73  
74  /*
75   * The total buffer space used by NIT.
76   */
77  #define BUFSPACE (4*CHUNKSIZE)
78  
79  /* Forwards */
80  static int nit_setflags(int, int, int, char *);
81  
82  /*
83   * Private data for capturing on STREAMS NIT devices.
84   */
85  struct pcap_snit {
86  	struct pcap_stat stat;
87  };
88  
89  static int
pcap_stats_snit(pcap_t * p,struct pcap_stat * ps)90  pcap_stats_snit(pcap_t *p, struct pcap_stat *ps)
91  {
92  	struct pcap_snit *psn = p->priv;
93  
94  	/*
95  	 * "ps_recv" counts packets handed to the filter, not packets
96  	 * that passed the filter.  As filtering is done in userland,
97  	 * this does not include packets dropped because we ran out
98  	 * of buffer space.
99  	 *
100  	 * "ps_drop" counts packets dropped inside the "/dev/nit"
101  	 * device because of flow control requirements or resource
102  	 * exhaustion; it doesn't count packets dropped by the
103  	 * interface driver, or packets dropped upstream.  As filtering
104  	 * is done in userland, it counts packets regardless of whether
105  	 * they would've passed the filter.
106  	 *
107  	 * These statistics don't include packets not yet read from the
108  	 * kernel by libpcap or packets not yet read from libpcap by the
109  	 * application.
110  	 */
111  	*ps = psn->stat;
112  	return (0);
113  }
114  
115  static int
pcap_read_snit(pcap_t * p,int cnt,pcap_handler callback,u_char * user)116  pcap_read_snit(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
117  {
118  	struct pcap_snit *psn = p->priv;
119  	register int cc, n;
120  	register u_char *bp, *cp, *ep;
121  	register struct nit_bufhdr *hdrp;
122  	register struct nit_iftime *ntp;
123  	register struct nit_iflen *nlp;
124  	register struct nit_ifdrops *ndp;
125  	register int caplen;
126  
127  	cc = p->cc;
128  	if (cc == 0) {
129  		cc = read(p->fd, (char *)p->buffer, p->bufsize);
130  		if (cc < 0) {
131  			if (errno == EWOULDBLOCK)
132  				return (0);
133  			pcap_fmt_errmsg_for_errno(p->errbuf, sizeof(p->errbuf),
134  			    errno, "pcap_read");
135  			return (-1);
136  		}
137  		bp = (u_char *)p->buffer;
138  	} else
139  		bp = p->bp;
140  
141  	/*
142  	 * loop through each snapshot in the chunk
143  	 */
144  	n = 0;
145  	ep = bp + cc;
146  	while (bp < ep) {
147  		/*
148  		 * Has "pcap_breakloop()" been called?
149  		 * If so, return immediately - if we haven't read any
150  		 * packets, clear the flag and return -2 to indicate
151  		 * that we were told to break out of the loop, otherwise
152  		 * leave the flag set, so that the *next* call will break
153  		 * out of the loop without having read any packets, and
154  		 * return the number of packets we've processed so far.
155  		 */
156  		if (p->break_loop) {
157  			if (n == 0) {
158  				p->break_loop = 0;
159  				return (-2);
160  			} else {
161  				p->bp = bp;
162  				p->cc = ep - bp;
163  				return (n);
164  			}
165  		}
166  
167  		++psn->stat.ps_recv;
168  		cp = bp;
169  
170  		/* get past NIT buffer  */
171  		hdrp = (struct nit_bufhdr *)cp;
172  		cp += sizeof(*hdrp);
173  
174  		/* get past NIT timer   */
175  		ntp = (struct nit_iftime *)cp;
176  		cp += sizeof(*ntp);
177  
178  		ndp = (struct nit_ifdrops *)cp;
179  		psn->stat.ps_drop = ndp->nh_drops;
180  		cp += sizeof *ndp;
181  
182  		/* get past packet len  */
183  		nlp = (struct nit_iflen *)cp;
184  		cp += sizeof(*nlp);
185  
186  		/* next snapshot        */
187  		bp += hdrp->nhb_totlen;
188  
189  		caplen = nlp->nh_pktlen;
190  		if (caplen > p->snapshot)
191  			caplen = p->snapshot;
192  
193  		if (bpf_filter(p->fcode.bf_insns, cp, nlp->nh_pktlen, caplen)) {
194  			struct pcap_pkthdr h;
195  			h.ts = ntp->nh_timestamp;
196  			h.len = nlp->nh_pktlen;
197  			h.caplen = caplen;
198  			(*callback)(user, &h, cp);
199  			if (++n >= cnt && !PACKET_COUNT_IS_UNLIMITED(cnt)) {
200  				p->cc = ep - bp;
201  				p->bp = bp;
202  				return (n);
203  			}
204  		}
205  	}
206  	p->cc = 0;
207  	return (n);
208  }
209  
210  static int
pcap_inject_snit(pcap_t * p,const void * buf,size_t size)211  pcap_inject_snit(pcap_t *p, const void *buf, size_t size)
212  {
213  	struct strbuf ctl, data;
214  
215  	/*
216  	 * XXX - can we just do
217  	 *
218  	ret = write(pd->f, buf, size);
219  	 */
220  	ctl.len = sizeof(*sa);	/* XXX - what was this? */
221  	ctl.buf = (char *)sa;
222  	data.buf = buf;
223  	data.len = size;
224  	ret = putmsg(p->fd, &ctl, &data);
225  	if (ret == -1) {
226  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
227  		    errno, "send");
228  		return (-1);
229  	}
230  	return (ret);
231  }
232  
233  static int
nit_setflags(pcap_t * p)234  nit_setflags(pcap_t *p)
235  {
236  	bpf_u_int32 flags;
237  	struct strioctl si;
238  	u_int zero = 0;
239  	struct timeval timeout;
240  
241  	if (p->opt.immediate) {
242  		/*
243  		 * Set the chunk size to zero, so that chunks get sent
244  		 * up immediately.
245  		 */
246  		si.ic_cmd = NIOCSCHUNK;
247  		si.ic_len = sizeof(zero);
248  		si.ic_dp = (char *)&zero;
249  		if (ioctl(p->fd, I_STR, (char *)&si) < 0) {
250  			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
251  			    errno, "NIOCSCHUNK");
252  			return (-1);
253  		}
254  	}
255  	si.ic_timout = INFTIM;
256  	if (p->opt.timeout != 0) {
257  		timeout.tv_sec = p->opt.timeout / 1000;
258  		timeout.tv_usec = (p->opt.timeout * 1000) % 1000000;
259  		si.ic_cmd = NIOCSTIME;
260  		si.ic_len = sizeof(timeout);
261  		si.ic_dp = (char *)&timeout;
262  		if (ioctl(p->fd, I_STR, (char *)&si) < 0) {
263  			pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
264  			    errno, "NIOCSTIME");
265  			return (-1);
266  		}
267  	}
268  	flags = NI_TIMESTAMP | NI_LEN | NI_DROPS;
269  	if (p->opt.promisc)
270  		flags |= NI_PROMISC;
271  	si.ic_cmd = NIOCSFLAGS;
272  	si.ic_len = sizeof(flags);
273  	si.ic_dp = (char *)&flags;
274  	if (ioctl(p->fd, I_STR, (char *)&si) < 0) {
275  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
276  		    errno, "NIOCSFLAGS");
277  		return (-1);
278  	}
279  	return (0);
280  }
281  
282  static int
pcap_activate_snit(pcap_t * p)283  pcap_activate_snit(pcap_t *p)
284  {
285  	struct strioctl si;		/* struct for ioctl() */
286  	struct ifreq ifr;		/* interface request struct */
287  	int chunksize = CHUNKSIZE;
288  	int fd;
289  	static const char dev[] = "/dev/nit";
290  	int err;
291  
292  	if (p->opt.rfmon) {
293  		/*
294  		 * No monitor mode on SunOS 4.x (no Wi-Fi devices on
295  		 * hardware supported by SunOS 4.x).
296  		 */
297  		return (PCAP_ERROR_RFMON_NOTSUP);
298  	}
299  
300  	/*
301  	 * Turn a negative snapshot value (invalid), a snapshot value of
302  	 * 0 (unspecified), or a value bigger than the normal maximum
303  	 * value, into the maximum allowed value.
304  	 *
305  	 * If some application really *needs* a bigger snapshot
306  	 * length, we should just increase MAXIMUM_SNAPLEN.
307  	 */
308  	if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
309  		p->snapshot = MAXIMUM_SNAPLEN;
310  
311  	if (p->snapshot < 96)
312  		/*
313  		 * NIT requires a snapshot length of at least 96.
314  		 */
315  		p->snapshot = 96;
316  
317  	/*
318  	 * Initially try a read/write open (to allow the inject
319  	 * method to work).  If that fails due to permission
320  	 * issues, fall back to read-only.  This allows a
321  	 * non-root user to be granted specific access to pcap
322  	 * capabilities via file permissions.
323  	 *
324  	 * XXX - we should have an API that has a flag that
325  	 * controls whether to open read-only or read-write,
326  	 * so that denial of permission to send (or inability
327  	 * to send, if sending packets isn't supported on
328  	 * the device in question) can be indicated at open
329  	 * time.
330  	 */
331  	p->fd = fd = open(dev, O_RDWR);
332  	if (fd < 0 && errno == EACCES)
333  		p->fd = fd = open(dev, O_RDONLY);
334  	if (fd < 0) {
335  		if (errno == EACCES)
336  			err = PCAP_ERROR_PERM_DENIED;
337  		else
338  			err = PCAP_ERROR;
339  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
340  		    errno, "%s", dev);
341  		goto bad;
342  	}
343  
344  	/* arrange to get discrete messages from the STREAM and use NIT_BUF */
345  	if (ioctl(fd, I_SRDOPT, (char *)RMSGD) < 0) {
346  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
347  		    errno, "I_SRDOPT");
348  		err = PCAP_ERROR;
349  		goto bad;
350  	}
351  	if (ioctl(fd, I_PUSH, "nbuf") < 0) {
352  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
353  		    errno, "push nbuf");
354  		err = PCAP_ERROR;
355  		goto bad;
356  	}
357  	/* set the chunksize */
358  	si.ic_cmd = NIOCSCHUNK;
359  	si.ic_timout = INFTIM;
360  	si.ic_len = sizeof(chunksize);
361  	si.ic_dp = (char *)&chunksize;
362  	if (ioctl(fd, I_STR, (char *)&si) < 0) {
363  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
364  		    errno, "NIOCSCHUNK");
365  		err = PCAP_ERROR;
366  		goto bad;
367  	}
368  
369  	/* request the interface */
370  	strncpy(ifr.ifr_name, p->opt.device, sizeof(ifr.ifr_name));
371  	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
372  	si.ic_cmd = NIOCBIND;
373  	si.ic_len = sizeof(ifr);
374  	si.ic_dp = (char *)&ifr;
375  	if (ioctl(fd, I_STR, (char *)&si) < 0) {
376  		/*
377  		 * XXX - is there an error that means "no such device"?
378  		 * Is there one that means "that device doesn't support
379  		 * STREAMS NIT"?
380  		 */
381  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
382  		    errno, "NIOCBIND: %s", ifr.ifr_name);
383  		err = PCAP_ERROR;
384  		goto bad;
385  	}
386  
387  	/* set the snapshot length */
388  	si.ic_cmd = NIOCSSNAP;
389  	si.ic_len = sizeof(p->snapshot);
390  	si.ic_dp = (char *)&p->snapshot;
391  	if (ioctl(fd, I_STR, (char *)&si) < 0) {
392  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
393  		    errno, "NIOCSSNAP");
394  		err = PCAP_ERROR;
395  		goto bad;
396  	}
397  	if (nit_setflags(p) < 0) {
398  		err = PCAP_ERROR;
399  		goto bad;
400  	}
401  
402  	(void)ioctl(fd, I_FLUSH, (char *)FLUSHR);
403  	/*
404  	 * NIT supports only ethernets.
405  	 */
406  	p->linktype = DLT_EN10MB;
407  
408  	p->bufsize = BUFSPACE;
409  	p->buffer = malloc(p->bufsize);
410  	if (p->buffer == NULL) {
411  		pcap_fmt_errmsg_for_errno(p->errbuf, PCAP_ERRBUF_SIZE,
412  		    errno, "malloc");
413  		err = PCAP_ERROR;
414  		goto bad;
415  	}
416  
417  	/*
418  	 * "p->fd" is an FD for a STREAMS device, so "select()" and
419  	 * "poll()" should work on it.
420  	 */
421  	p->selectable_fd = p->fd;
422  
423  	/*
424  	 * This is (presumably) a real Ethernet capture; give it a
425  	 * link-layer-type list with DLT_EN10MB and DLT_DOCSIS, so
426  	 * that an application can let you choose it, in case you're
427  	 * capturing DOCSIS traffic that a Cisco Cable Modem
428  	 * Termination System is putting out onto an Ethernet (it
429  	 * doesn't put an Ethernet header onto the wire, it puts raw
430  	 * DOCSIS frames out on the wire inside the low-level
431  	 * Ethernet framing).
432  	 */
433  	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
434  	/*
435  	 * If that fails, just leave the list empty.
436  	 */
437  	if (p->dlt_list != NULL) {
438  		p->dlt_list[0] = DLT_EN10MB;
439  		p->dlt_list[1] = DLT_DOCSIS;
440  		p->dlt_count = 2;
441  	}
442  
443  	p->read_op = pcap_read_snit;
444  	p->inject_op = pcap_inject_snit;
445  	p->setfilter_op = install_bpf_program;	/* no kernel filtering */
446  	p->setdirection_op = NULL;	/* Not implemented. */
447  	p->set_datalink_op = NULL;	/* can't change data link type */
448  	p->getnonblock_op = pcap_getnonblock_fd;
449  	p->setnonblock_op = pcap_setnonblock_fd;
450  	p->stats_op = pcap_stats_snit;
451  
452  	return (0);
453   bad:
454  	pcap_cleanup_live_common(p);
455  	return (err);
456  }
457  
458  pcap_t *
pcap_create_interface(const char * device _U_,char * ebuf)459  pcap_create_interface(const char *device _U_, char *ebuf)
460  {
461  	pcap_t *p;
462  
463  	p = pcap_create_common(ebuf, sizeof (struct pcap_snit));
464  	if (p == NULL)
465  		return (NULL);
466  
467  	p->activate_op = pcap_activate_snit;
468  	return (p);
469  }
470  
471  /*
472   * XXX - there's probably a NIOCBIND error that means "that device
473   * doesn't support NIT"; if so, we should try an NIOCBIND and use that.
474   */
475  static int
can_be_bound(const char * name _U_)476  can_be_bound(const char *name _U_)
477  {
478  	return (1);
479  }
480  
481  static int
get_if_flags(const char * name _U_,bpf_u_int32 * flags _U_,char * errbuf _U_)482  get_if_flags(const char *name _U_, bpf_u_int32 *flags _U_, char *errbuf _U_)
483  {
484  	/*
485  	 * Nothing we can do.
486  	 * XXX - is there a way to find out whether an adapter has
487  	 * something plugged into it?
488  	 */
489  	return (0);
490  }
491  
492  int
pcap_platform_finddevs(pcap_if_list_t * devlistp,char * errbuf)493  pcap_platform_finddevs(pcap_if_list_t *devlistp, char *errbuf)
494  {
495  	return (pcap_findalldevs_interfaces(devlistp, errbuf, can_be_bound,
496  	    get_if_flags));
497  }
498  
499  /*
500   * Libpcap version string.
501   */
502  const char *
pcap_lib_version(void)503  pcap_lib_version(void)
504  {
505  	return (PCAP_VERSION_STRING);
506  }
507