xref: /386bsd/usr/src/usr.sbin/tcpdump/pcap-nit.c (revision a2142627)
1 /*
2  * Copyright (c) 1988, 1990 The Regents of the University of California.
3  * 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  char rcsid[] =
23     "@(#)$Header: pcap-nit.c,v 1.12 90/12/04 17:13:24 mccanne Exp $ (LBL)";
24 #endif
25 
26 #include <stdio.h>
27 #include <netdb.h>
28 #include <ctype.h>
29 #include <signal.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/time.h>
33 #include <sys/timeb.h>
34 #include <sys/socket.h>
35 #include <sys/file.h>
36 #include <sys/ioctl.h>
37 #include <net/nit.h>
38 
39 #include <net/if.h>
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 #include <net/bpf.h>
50 
51 #include "interface.h"
52 
53 /*
54  * The chunk size for NIT.  This is the amount of buffering
55  * done for read calls.
56  */
57 #define CHUNKSIZE (2*1024)
58 
59 /*
60  * The total buffer space used by NIT.
61  */
62 #define BUFSPACE (4*CHUNKSIZE)
63 
64 void
readloop(cnt,if_fd,fp,printit)65 readloop(cnt, if_fd, fp, printit)
66 	int cnt;
67 	int if_fd;
68 	struct bpf_program *fp;
69 	void (*printit)();
70 {
71 	u_char buf[CHUNKSIZE];
72 	struct bpf_insn *fcode;
73 	int cc, i;
74 
75 	fcode = fp->bf_insns;
76 	i = 0;
77 
78 	while ((cc = read(if_fd, (char *)buf, sizeof(buf))) > 0) {
79 		register u_char *bp, *bstop;
80 		register u_char *sp;
81 		register struct nit_hdr *nh;
82 		register int datalen = 0;
83 		int caplen;
84 
85 		/*
86 		 * Loop through each packet.  The increment expression
87 		 * rounds up to the next int boundary past the end of
88 		 * the previous packet.
89 		 */
90 		bstop = buf + cc;
91 		for (bp = buf; bp < bstop;
92 		     bp += ((sizeof(struct nit_hdr)+datalen+sizeof(int)-1)
93 			    & ~(sizeof(int)-1))) {
94 
95 			nh = (struct nit_hdr *)bp;
96 			sp = bp + sizeof(*nh);
97 
98 			switch (nh->nh_state) {
99 			case NIT_CATCH:
100 				datalen = nh->nh_datalen;
101 				break;
102 			case NIT_SEQNO:
103 			case NIT_NOMBUF:
104 			case NIT_NOCLUSTER:
105 			case NIT_NOSPACE:
106 				datalen = 0;
107 				continue;
108 			default:
109 				(void)fprintf(stderr,
110 				      "bad nit state %d\n", nh->nh_state);
111 				exit(1);
112 			}
113 			caplen = nh->nh_wirelen;
114 			if (caplen > snaplen)
115 				caplen = snaplen;
116 			if (bpf_filter(fcode, sp, nh->nh_wirelen, caplen)) {
117 				(*printit)(sp, &nh->nh_timestamp,
118 					   nh->nh_wirelen, caplen);
119 				if (cflag && ++i >= cnt) {
120 					wrapup(if_fd);
121 					return;
122 				}
123 			}
124 		}
125 	}
126 	perror("read");
127 	exit(-1);
128 }
129 
wrapup(fd)130 wrapup(fd)
131 	int fd;
132 {
133 	close(fd);
134 }
135 
136 int
initdevice(device,pflag,linktype)137 initdevice(device, pflag, linktype)
138 	char *device;
139 	int pflag;
140 	int *linktype;
141 {
142 	struct sockaddr_nit snit;
143 	struct nit_ioc nioc;
144 	int if_fd;
145 
146 	if (snaplen < 96)
147 		/*
148 		 * NIT requires a snapshot length of at least 96.
149 		 */
150 		snaplen = 96;
151 
152 	if_fd = socket(AF_NIT, SOCK_RAW, NITPROTO_RAW);
153 
154 	if (if_fd < 0) {
155 		perror("nit socket");
156 		exit(-1);
157 	}
158 
159 	snit.snit_family = AF_NIT;
160 	(void)strncpy(snit.snit_ifname, device, NITIFSIZ);
161 
162 	if (bind(if_fd, (struct sockaddr *)&snit, sizeof(snit))) {
163 		perror(snit.snit_ifname);
164 		exit(1);
165 	}
166 
167 	bzero((char *)&nioc, sizeof(nioc));
168 	nioc.nioc_bufspace = BUFSPACE;
169 	nioc.nioc_chunksize = CHUNKSIZE;
170 	nioc.nioc_typetomatch = NT_ALLTYPES;
171 	nioc.nioc_snaplen = snaplen;
172 	nioc.nioc_bufalign = sizeof(int);
173 	nioc.nioc_bufoffset = 0;
174 	nioc.nioc_flags = pflag ? NF_TIMEOUT : NF_PROMISC|NF_TIMEOUT;
175 	nioc.nioc_timeout.tv_sec = 1;
176 	nioc.nioc_timeout.tv_usec = 0;
177 
178 	if (ioctl(if_fd, SIOCSNIT, &nioc) != 0) {
179 		perror("nit ioctl");
180 		exit(1);
181 	}
182 	/*
183 	 * NIT supports only ethernets.
184 	 */
185 	*linktype = DLT_EN10MB;
186 
187 	return if_fd;
188 }
189