]>
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.15 1999-10-07 23:46:40 mcr 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 sprintf(p
->errbuf
, "read: %s", pcap_strerror(errno
));
102 } while (strcmp(p
->md
.device
, from
.sa_data
));
104 /* If we need have leading zero bytes, adjust count */
106 bp
= p
->buffer
+ p
->offset
;
108 /* If we need to step over leading junk, adjust count and pointer */
112 /* Captured length can't exceed our read buffer size */
114 if (caplen
> bufsize
)
117 /* Captured length can't exceed the snapshot length */
118 if (caplen
> p
->snapshot
)
119 caplen
= p
->snapshot
;
121 if (p
->fcode
.bf_insns
== NULL
||
122 bpf_filter(p
->fcode
.bf_insns
, bp
, cc
, caplen
)) {
123 struct pcap_pkthdr h
;
125 ++p
->md
.stat
.ps_recv
;
127 if (ioctl(p
->fd
, SIOCGSTAMP
, &h
.ts
) < 0) {
128 sprintf(p
->errbuf
, "SIOCGSTAMP: %s",
129 pcap_strerror(errno
));
134 (*callback
)(user
, &h
, bp
);
141 pcap_open_live(char *device
, int snaplen
, int promisc
, int to_ms
, char *ebuf
)
143 register int fd
, broadcast
;
148 p
= (pcap_t
*)malloc(sizeof(*p
));
150 sprintf(ebuf
, "malloc: %s", pcap_strerror(errno
));
153 memset(p
, 0, sizeof(*p
));
156 fd
= socket(PF_INET
, SOCK_PACKET
, htons(ETH_P_ALL
));
158 sprintf(ebuf
, "socket: %s", pcap_strerror(errno
));
163 /* Bind to the interface name */
164 memset(&sa
, 0, sizeof(sa
));
165 sa
.sa_family
= AF_INET
;
166 (void)strncpy(sa
.sa_data
, device
, sizeof(sa
.sa_data
));
167 if (bind(p
->fd
, &sa
, sizeof(sa
))) {
168 sprintf(ebuf
, "bind: %s: %s", device
, pcap_strerror(errno
));
172 memset(&ifr
, 0, sizeof(ifr
));
173 strncpy(ifr
.ifr_name
, device
, sizeof(ifr
.ifr_name
));
174 if (ioctl(p
->fd
, SIOCGIFHWADDR
, &ifr
) < 0 ) {
175 sprintf(ebuf
, "SIOCGIFHWADDR: %s", pcap_strerror(errno
));
179 switch (ifr
.ifr_hwaddr
.sa_family
) {
182 case ARPHRD_METRICOM
:
183 p
->linktype
= DLT_EN10MB
;
189 p
->linktype
= DLT_EN3MB
;
194 p
->linktype
= DLT_AX25
;
199 p
->linktype
= DLT_PRONET
;
203 p
->linktype
= DLT_CHAOS
;
207 p
->linktype
= DLT_IEEE802
;
212 p
->linktype
= DLT_ARCNET
;
221 p
->linktype
= DLT_RAW
;
224 case ARPHRD_LOOPBACK
:
225 p
->linktype
= DLT_NULL
;
231 /* Not all versions of the kernel has this define */
233 p
->linktype
= DLT_FDDI
;
239 case ARPHRD_LOCALTLK
:
241 case ARPHRD_APPLETLK
:
249 /* XXX currently do not know what to do with these... */
254 sprintf(ebuf
, "unknown physical layer type 0x%x",
255 ifr
.ifr_hwaddr
.sa_family
);
259 /* Base the buffer size on the interface MTU */
260 memset(&ifr
, 0, sizeof(ifr
));
261 strncpy(ifr
.ifr_name
, device
, sizeof(ifr
.ifr_name
));
262 if (ioctl(p
->fd
, SIOCGIFMTU
, &ifr
) < 0 ) {
263 sprintf(ebuf
, "SIOCGIFMTU: %s", pcap_strerror(errno
));
267 /* Leave room for link header (which is never large under linux...) */
268 p
->bufsize
= ifr
.ifr_mtu
+ 64;
270 p
->buffer
= (u_char
*)malloc(p
->bufsize
+ p
->offset
);
271 if (p
->buffer
== NULL
) {
272 sprintf(ebuf
, "malloc: %s", pcap_strerror(errno
));
277 if (promisc
&& broadcast
) {
278 memset(&ifr
, 0, sizeof(ifr
));
279 strcpy(ifr
.ifr_name
, device
);
280 if (ioctl(p
->fd
, SIOCGIFFLAGS
, &ifr
) < 0 ) {
281 sprintf(ebuf
, "SIOCGIFFLAGS: %s", pcap_strerror(errno
));
285 ifr
.ifr_flags
|= IFF_PROMISC
;
286 if (ioctl(p
->fd
, SIOCSIFFLAGS
, &ifr
) < 0 ) {
287 sprintf(ebuf
, "SIOCSIFFLAGS: %s", pcap_strerror(errno
));
290 ifr
.ifr_flags
&= ~IFF_PROMISC
;
291 atexit(linux_restore_ifr
);
294 p
->md
.device
= strdup(device
);
295 if (p
->md
.device
== NULL
) {
296 sprintf(ebuf
, "malloc: %s", pcap_strerror(errno
));
299 p
->snapshot
= snaplen
;
305 if (p
->buffer
!= NULL
)
307 if (p
->md
.device
!= NULL
)
314 pcap_setfilter(pcap_t
*p
, struct bpf_program
*fp
)
322 linux_restore_ifr(void)
326 fd
= socket(PF_INET
, SOCK_PACKET
, htons(0x0003));
328 fprintf(stderr
, "linux socket: %s", pcap_strerror(errno
));
329 else if (ioctl(fd
, SIOCSIFFLAGS
, &saved_ifr
) < 0)
330 fprintf(stderr
, "linux SIOCSIFFLAGS: %s", pcap_strerror(errno
));