]>
The Tcpdump Group git mirrors - libpcap/blob - pcap-linux.c
2 * Copyright (c) 1996, 1997
3 * The Regents of the University of California. All rights reserved.
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
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.
22 static const char rcsid
[] =
23 "@(#) $Header: /tcpdump/master/libpcap/pcap-linux.c,v 1.16 2000-04-27 09:11:13 itojun Exp $ (LBL)";
26 #include <sys/param.h>
27 #include <sys/ioctl.h>
28 #include <sys/socket.h>
32 #ifdef HAVE_NET_IF_ARP_H
33 #include <net/if_arp.h>
35 #include <linux/if_arp.h>
37 #include <linux/if_ether.h>
39 #include <netinet/in.h>
48 static struct ifreq saved_ifr
;
53 #ifdef HAVE_OS_PROTO_H
57 void linux_restore_ifr(void);
60 pcap_stats(pcap_t
*p
, struct pcap_stat
*ps
)
68 pcap_read(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
)
77 bp
= p
->buffer
+ p
->offset
;
80 memset(bp
, 0, p
->md
.pad
);
87 fromlen
= sizeof(from
);
88 cc
= recvfrom(p
->fd
, bp
, bufsize
, 0, &from
, &fromlen
);
90 /* Don't choke when we get ptraced */
99 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
100 "read: %s", pcap_strerror(errno
));
103 } while (strcmp(p
->md
.device
, from
.sa_data
));
105 /* If we need have leading zero bytes, adjust count */
107 bp
= p
->buffer
+ p
->offset
;
109 /* If we need to step over leading junk, adjust count and pointer */
113 /* Captured length can't exceed our read buffer size */
115 if (caplen
> bufsize
)
118 /* Captured length can't exceed the snapshot length */
119 if (caplen
> p
->snapshot
)
120 caplen
= p
->snapshot
;
122 if (p
->fcode
.bf_insns
== NULL
||
123 bpf_filter(p
->fcode
.bf_insns
, bp
, cc
, caplen
)) {
124 struct pcap_pkthdr h
;
126 ++p
->md
.stat
.ps_recv
;
128 if (ioctl(p
->fd
, SIOCGSTAMP
, &h
.ts
) < 0) {
129 snprintf(p
->errbuf
, sizeof(p
->errbuf
), "SIOCGSTAMP: %s",
130 pcap_strerror(errno
));
135 (*callback
)(user
, &h
, bp
);
142 pcap_open_live(char *device
, int snaplen
, int promisc
, int to_ms
, char *ebuf
)
144 register int fd
, broadcast
;
149 p
= (pcap_t
*)malloc(sizeof(*p
));
151 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, PCAP_ERRBUFF_SIZE
,
152 "malloc: %s", pcap_strerror(errno
));
155 memset(p
, 0, sizeof(*p
));
158 fd
= socket(PF_INET
, SOCK_PACKET
, htons(ETH_P_ALL
));
160 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "socket: %s",
161 pcap_strerror(errno
));
166 /* Bind to the interface name */
167 memset(&sa
, 0, sizeof(sa
));
168 sa
.sa_family
= AF_INET
;
169 (void)strncpy(sa
.sa_data
, device
, sizeof(sa
.sa_data
));
170 if (bind(p
->fd
, &sa
, sizeof(sa
))) {
171 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "bind: %s: %s", device
,
172 pcap_strerror(errno
));
176 memset(&ifr
, 0, sizeof(ifr
));
177 strncpy(ifr
.ifr_name
, device
, sizeof(ifr
.ifr_name
));
178 if (ioctl(p
->fd
, SIOCGIFHWADDR
, &ifr
) < 0 ) {
179 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "SIOCGIFHWADDR: %s",
180 pcap_strerror(errno
));
184 switch (ifr
.ifr_hwaddr
.sa_family
) {
187 case ARPHRD_METRICOM
:
188 p
->linktype
= DLT_EN10MB
;
194 p
->linktype
= DLT_EN3MB
;
199 p
->linktype
= DLT_AX25
;
204 p
->linktype
= DLT_PRONET
;
208 p
->linktype
= DLT_CHAOS
;
212 p
->linktype
= DLT_IEEE802
;
217 p
->linktype
= DLT_ARCNET
;
226 p
->linktype
= DLT_RAW
;
229 case ARPHRD_LOOPBACK
:
230 p
->linktype
= DLT_NULL
;
236 /* Not all versions of the kernel has this define */
238 p
->linktype
= DLT_FDDI
;
244 case ARPHRD_LOCALTLK
:
246 case ARPHRD_APPLETLK
:
254 /* XXX currently do not know what to do with these... */
259 snprint(ebuf
, PCAP_ERRBUFF_SIZE
,
260 "unknown physical layer type 0x%x",
261 ifr
.ifr_hwaddr
.sa_family
);
265 /* Base the buffer size on the interface MTU */
266 memset(&ifr
, 0, sizeof(ifr
));
267 strncpy(ifr
.ifr_name
, device
, sizeof(ifr
.ifr_name
));
268 if (ioctl(p
->fd
, SIOCGIFMTU
, &ifr
) < 0 ) {
269 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "SIOCGIFMTU: %s",
270 pcap_strerror(errno
));
274 /* Leave room for link header (which is never large under linux...) */
275 p
->bufsize
= ifr
.ifr_mtu
+ 64;
277 p
->buffer
= (u_char
*)malloc(p
->bufsize
+ p
->offset
);
278 if (p
->buffer
== NULL
) {
279 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "malloc: %s",
280 pcap_strerror(errno
));
285 if (promisc
&& broadcast
) {
286 memset(&ifr
, 0, sizeof(ifr
));
287 strcpy(ifr
.ifr_name
, device
);
288 if (ioctl(p
->fd
, SIOCGIFFLAGS
, &ifr
) < 0 ) {
289 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "SIOCGIFFLAGS: %s",
290 pcap_strerror(errno
));
294 ifr
.ifr_flags
|= IFF_PROMISC
;
295 if (ioctl(p
->fd
, SIOCSIFFLAGS
, &ifr
) < 0 ) {
296 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "SIOCSIFFLAGS: %s",
297 pcap_strerror(errno
));
300 ifr
.ifr_flags
&= ~IFF_PROMISC
;
301 atexit(linux_restore_ifr
);
304 p
->md
.device
= strdup(device
);
305 if (p
->md
.device
== NULL
) {
306 snprint(ebuf
, PCAP_ERRBUFF_SIZE
, "malloc: %s",
307 pcap_strerror(errno
));
310 p
->snapshot
= snaplen
;
316 if (p
->buffer
!= NULL
)
318 if (p
->md
.device
!= NULL
)
325 pcap_setfilter(pcap_t
*p
, struct bpf_program
*fp
)
333 linux_restore_ifr(void)
337 fd
= socket(PF_INET
, SOCK_PACKET
, htons(0x0003));
339 fprintf(stderr
, "linux socket: %s", pcap_strerror(errno
));
340 else if (ioctl(fd
, SIOCSIFFLAGS
, &saved_ifr
) < 0)
341 fprintf(stderr
, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno
));