]> The Tcpdump Group git mirrors - libpcap/blob - pcap-linux.c
add config.h, remove gnuc.h. remove __dead
[libpcap] / pcap-linux.c
1 /*
2 pcap-linux.c: Packet capture interface to the Linux kernel
3 Copyright (c) 2000 Torsten Landschoff <torsten@debian.org>
4 Sebastian Krahmer <krahmer@cs.uni-potsdam.de>
5
6 License: BSD
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
10 are met:
11
12 1. Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
14 2. Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18 3. The names of the authors may not be used to endorse or promote
19 products derived from this software without specific prior
20 written permission.
21
22 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 */
26
27 /*
28 TODO:
29
30 - Make it compatible with older Linux installations (at compilation time)
31
32 BUGS:
33
34 - setting promiscuous on loopback for example gives every packet
35 twice
36 */
37
38
39 /*
40 FYI:
41
42 pcap_read currently reads not only a packet from the kernel but also
43 the sockaddr_ll returned as source of the packet. This way we can at
44 some time extend tcpdump and libpcap to sniff on all devices at a time
45 and find the right printing routine by using the information in the
46 sockaddr_ll structure.
47 */
48
49
50 #ifdef HAVE_CONFIG_H
51 #include "config.h"
52 #endif
53
54 #include "pcap-int.h"
55
56 #include <errno.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <string.h>
61 #include <sys/socket.h>
62 #include <sys/ioctl.h>
63 #include <net/if.h>
64 #include <netinet/in.h>
65 #include <linux/if_ether.h>
66 #include <netinet/if_ether.h>
67
68 #ifdef HAVE_NETPACKET_PACKET_H
69 #include <netpacket/packet.h>
70 #endif
71 #ifdef SO_ATTACH_FILTER
72 #include <linux/types.h>
73 #include <linux/filter.h>
74 #endif
75
76 #ifndef __GLIBC__
77 typedef int socklen_t;
78 #define MSG_TRUNC 0
79 #endif
80
81 #define MAX_LINKHEADER_SIZE 256
82
83 /* Prototypes for internal functions */
84 static int map_arphrd_to_dlt( int arptype );
85 static int live_open_old( pcap_t *, char *, int, int, char * );
86 static int live_open_new( pcap_t *, char *, int, int, char * );
87 static int pcap_read_packet( pcap_t *, pcap_handler, u_char * );
88
89 /* Wrap some ioctl calls */
90 static int iface_get_id( int fd, const char *device, char *ebuf );
91 static int iface_get_mtu( int fd, const char *device, char *ebuf );
92 static int iface_get_arptype( int fd, const char *device, char *ebuf );
93 static int iface_bind( int fd, int ifindex, char *ebuf );
94 static int iface_bind_old( int fd, const char *device, char *ebuf );
95
96 /*
97 pcap_open_live:
98
99 Get a handle for a live capture from the given device. You can
100 pass NULL as device to get all packages (without link level
101 information of course). If you pass 1 as promisc the interface
102 will be set to promiscous mode (XXX: I think this usage should
103 be deprecated and functions be added to select that later allow
104 modification of that values -- Torsten).
105
106 See also pcap(3).
107 */
108 pcap_t *
109 pcap_open_live( char *device, int snaplen, int promisc, int to_ms, char *ebuf )
110 {
111 /* Allocate a handle for this session. */
112
113 pcap_t *handle = malloc(sizeof(*handle));
114 if( handle == NULL ) {
115 snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s",
116 pcap_strerror(errno));
117 return NULL;
118 }
119
120 /* Initialize some components of the pcap structure. */
121
122 memset( handle, 0, sizeof(*handle) );
123 handle->snapshot = snaplen;
124 handle->md.timeout = to_ms;
125 handle->md.promisc = promisc;
126 handle->md.device = strdup( device );
127 if( handle->md.device == NULL ) {
128 snprintf(ebuf, PCAP_ERRBUF_SIZE, "strdup: %s",
129 pcap_strerror(errno) );
130 free( handle );
131 return NULL;
132 }
133
134 /* Current Linux kernels use the protocol family PF_PACKET to
135 * allow direct access to all packets on the network while
136 * older kernels had a special socket type SOCK_PACKET to
137 * implement this feature.
138 * While this old implementation is kind of obsolete we need
139 * to be compatible with older kernels for a while so we are
140 * trying both methods with the newer method preferred. */
141
142 if( ! (live_open_new(handle, device, promisc, to_ms, ebuf) ||
143 live_open_old(handle, device, promisc, to_ms, ebuf)) )
144 {
145 /* Both methods to open the packet socket failed. Tidy
146 * up and report our failure (ebuf is expected to be
147 * set by the functions above). */
148
149 free(handle->md.device);
150 free( handle );
151 return NULL;
152 }
153
154 /* Okay, now we have a packet stream open. Maybe we need to handle
155 * a timeout? In that case we set the filehandle to nonblocking
156 * so pcap_read can try reading the fd and call select if no data
157 * is available at once. */
158
159 if( to_ms > 0 ) {
160 int flags = fcntl( handle->fd, F_GETFL );
161 if( flags != -1 ) {
162 flags |= O_NONBLOCK;
163 flags = fcntl( handle->fd, F_SETFL, flags );
164 }
165 if( flags == -1 ) {
166 snprintf(ebuf, PCAP_ERRBUF_SIZE, "fcntl: %s",
167 pcap_strerror(errno));
168 pcap_close( handle );
169 return NULL;
170 }
171 }
172
173 return handle;
174 }
175
176 /*
177 pcap_read:
178
179 Read at most max_packets from the capture stream and
180 call the callback for each of them. Returns the number
181 of packets handled or -1 if an error occured.
182
183 XXX: Can I rely on the Linux-specified behaviour of select
184 (returning the time left in the timeval structure)? I really
185 don't want to query the system time before each select call...
186 */
187 int
188 pcap_read(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
189 {
190 int status, packets;
191 fd_set read_fds;
192 struct timeval tv;
193
194 if( handle->md.timeout > 0 ) {
195 tv.tv_usec = (handle->md.timeout % 1000) * 1000;
196 tv.tv_sec = (handle->md.timeout / 1000);
197 }
198
199 for( packets = 0; max_packets == -1 || packets < max_packets; )
200 {
201 status = pcap_read_packet( handle, callback, user );
202
203 if( status > 0 ) {
204 packets++;
205 continue;
206 } else if( status == -1 )
207 return -1;
208
209 /* paranoia - the recvmsg call should block if we don't use
210 * a timeout */
211 if( handle->md.timeout <= 0 )
212 continue;
213
214 /* No packet available - go to sleep */
215 FD_ZERO( &read_fds );
216 FD_SET( handle->fd, &read_fds );
217 status = select( handle->fd + 1,
218 &read_fds, NULL, NULL, &tv );
219 if( status == -1 ) {
220 snprintf(handle->errbuf, sizeof(handle->errbuf),
221 "select: %s", pcap_strerror(errno));
222 return -1;
223 } else if( status == 0 ||
224 (tv.tv_usec == 0 && tv.tv_sec == 0) )
225 return packets;
226 }
227
228 return packets;
229 }
230
231 /*
232 pcap_read_packet:
233
234 Read a packet from the socket calling the handler provided by
235 the user. Returns 0 if no packet was there, 1 if a packet was
236 handled and -1 if an error occured.
237 */
238 static int
239 pcap_read_packet( pcap_t *handle, pcap_handler callback, u_char *userdata )
240 {
241 struct sockaddr from;
242 socklen_t fromlen;
243 int packet_len, caplen;
244 struct pcap_pkthdr pcap_header;
245
246 /* We don't currently use the from return value of recvfrom but
247 * this will probably implemented in the future. */
248
249 /* Receive a single packet from the kernel */
250 do {
251 fromlen = sizeof(from);
252 packet_len = recvfrom(
253 handle->fd, handle->buffer + handle->offset,
254 handle->snapshot, MSG_TRUNC,
255 (struct sockaddr *) &from, &fromlen );
256 } while( packet_len == -1 && errno == EINTR );
257
258 /* Check if some error occured */
259 if( packet_len == -1 ) {
260 if( errno == EAGAIN )
261 return 0; /* no packet there */
262 else {
263 snprintf(handle->errbuf, sizeof(handle->errbuf),
264 "recvfrom: %s", pcap_strerror(errno));
265 return -1;
266 }
267 }
268
269 /* XXX: According to the kernel source we should get the real
270 * packet len if calling recvfrom with MSG_TRUNC set. It does
271 * not seem to work here :(, but it is supported by this code
272 * anyway. */
273
274 caplen = packet_len;
275 if( caplen > handle->snapshot )
276 caplen = handle->snapshot;
277
278 /* Run the packet filter if not using kernel filter */
279 if( !handle->md.use_bpf && handle->fcode.bf_insns ) {
280 if( bpf_filter(handle->fcode.bf_insns, handle->buffer,
281 packet_len, caplen) == 0 )
282 {
283 /* rejected by filter */
284 return 0;
285 }
286 }
287
288 /* Fill in our own header data */
289
290 if( ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts) == -1 ) {
291 snprintf(handle->errbuf, sizeof(handle->errbuf),
292 "ioctl: %s", pcap_strerror(errno));
293 return -1;
294 }
295 pcap_header.caplen = caplen;
296 pcap_header.len = packet_len;
297
298 /* Call the user supplied callback function */
299 handle->md.stat.ps_recv++;
300 callback( userdata, &pcap_header, handle->buffer + handle->offset);
301
302 return 1;
303 }
304
305 /*
306 pcap_stats:
307
308 Get the statistics for the given packet capture handle.
309 */
310 int
311 pcap_stats( pcap_t *handle, struct pcap_stat *stats )
312 {
313 *stats = handle->md.stat;
314 return 0;
315 }
316
317 /*
318 pcap_setfilter:
319
320 Attach the given BPF code to the packet capture device.
321 */
322 int
323 pcap_setfilter( pcap_t *handle, struct bpf_program *filter )
324 {
325 #ifdef SO_ATTACH_FILTER
326 struct sock_fprog fcode;
327 #endif
328
329 if( !handle )
330 return -1;
331 if( !filter ) {
332 strncpy(handle->errbuf, "setfilter: No filter specified",
333 sizeof(handle->errbuf));
334 return -1;
335 }
336
337 /* Free old filter code if existing */
338 handle->fcode.bf_len = 0;
339 if( handle->fcode.bf_insns ) {
340 free( handle->fcode.bf_insns );
341 handle->fcode.bf_insns = NULL;
342 }
343
344
345 /* Make our private copy of the filter */
346 handle->fcode.bf_len = filter->bf_len;
347 handle->fcode.bf_insns =
348 malloc( filter->bf_len * sizeof(*filter->bf_insns) );
349 if( handle->fcode.bf_insns == NULL ) {
350 snprintf(handle->errbuf, sizeof(handle->errbuf),
351 "malloc: %s", pcap_strerror(errno));
352 return -1;
353 }
354 memcpy( handle->fcode.bf_insns, filter->bf_insns,
355 filter->bf_len * sizeof(*filter->bf_insns) );
356
357 /* Run user level packet filter by default. Will be overriden if
358 * installing a kernel filter succeeds. */
359 handle->md.use_bpf = 0;
360
361 /* Install kernel level filter if possible */
362
363 #ifdef SO_ATTACH_FILTER
364 /* Oh joy, the Linux kernel uses struct sock_fprog instead of
365 * struct bpf_program and of course the length field is of
366 * different size. Pointed out by Sebastian */
367
368 fcode.filter = (struct sock_filter *) handle->fcode.bf_insns;
369 fcode.len = filter->bf_len;
370 if( filter->bf_len > USHRT_MAX ) {
371 fprintf( stderr, "Warning: Filter to complex for kernel\n" );
372 /* paranoid - should never happen */
373 }
374 else if( setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
375 &fcode, sizeof(fcode)) == 0 )
376 {
377 handle->md.use_bpf = 1;
378 } else
379 {
380 /* Print a warning if kernel filter available but a problem
381 * occured using it. */
382 if( errno != ENOPROTOOPT && errno != EOPNOTSUPP ) {
383 fprintf( stderr, "Warning: Kernel filter failed: %s\n",
384 pcap_strerror(errno) );
385 }
386 }
387 #endif
388
389 return 0;
390 }
391
392
393 /*
394 map_arphrd_to_dlt:
395
396 Linux uses the ARP hardware type to identify the type of an
397 interface. pcap uses the DLT_xxx constants for this. This
398 function maps the ARPHRD_xxx constant to an appropriate
399 DLT_xxx constant.
400
401 Returns -1 if unable to map the type.
402 */
403 static int map_arphrd_to_dlt( int arptype )
404 {
405 switch( arptype ) {
406 case ARPHRD_ETHER:
407 case ARPHRD_METRICOM:
408 case ARPHRD_LOOPBACK: return DLT_EN10MB;
409 case ARPHRD_EETHER: return DLT_EN3MB;
410 case ARPHRD_AX25: return DLT_AX25;
411 case ARPHRD_PRONET: return DLT_PRONET;
412 case ARPHRD_CHAOS: return DLT_CHAOS;
413 case ARPHRD_IEEE802: return DLT_IEEE802;
414 case ARPHRD_ARCNET: return DLT_ARCNET;
415 case ARPHRD_FDDI: return DLT_FDDI;
416
417 case ARPHRD_PPP:
418 case ARPHRD_CSLIP:
419 case ARPHRD_SLIP6:
420 case ARPHRD_CSLIP6:
421 case ARPHRD_SLIP: return DLT_RAW;
422 }
423
424 return -1;
425 }
426
427 /* ===== Functions to interface to the newer kernels ================== */
428
429 /*
430 live_open_new:
431
432 Try to open a packet socket using the new kernel interface.
433 Returns 0 on failure.
434 FIXME: 0 uses to mean success (Sebastian)
435 */
436 static int
437 live_open_new( pcap_t *handle, char *device, int promisc,
438 int to_ms, char *ebuf )
439 {
440 #ifdef HAVE_NETPACKET_PACKET_H
441 int sock_fd = -1, device_id, mtu, arptype;
442 struct packet_mreq mr;
443
444 /* One shot loop used for error handling - bail out with break */
445
446 do {
447
448 /* Open a socket with protocol family packet. */
449 sock_fd = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL) );
450 if( sock_fd == -1 ) {
451 snprintf(ebuf, PCAP_ERRBUF_SIZE, "socket: %s",
452 pcap_strerror(errno) );
453 break;
454 }
455
456 /* It seems the kernel supports the new interface. */
457 handle->md.sock_packet = 0;
458
459 /* Currently we only support monitoring a single interface.
460 * While the kernel can do more I want to reimplement the
461 * old features first before adding more. */
462
463 if( !device ) {
464 snprintf(ebuf, PCAP_ERRBUF_SIZE,
465 "pcap_open_live: No device given" );
466 break;
467 }
468
469 /* What kind of frames do we have to deal with? Fall back
470 * to cooked mode if we have an unknown interface type. */
471
472 arptype = iface_get_arptype(sock_fd, device, ebuf);
473 if( arptype == -1 )
474 break;
475 handle->linktype = map_arphrd_to_dlt( arptype );
476 if( handle->linktype == -1 ) {
477 /* Unknown interface type - reopen in cooked mode */
478
479 if( close(sock_fd) == -1 ) {
480 snprintf(ebuf, PCAP_ERRBUF_SIZE,
481 "close: %s", pcap_strerror(errno));
482 break;
483 }
484 sock_fd = socket( PF_PACKET, SOCK_DGRAM,
485 htons(ETH_P_ALL) );
486 if( sock_fd == -1 ) {
487 snprintf(ebuf, PCAP_ERRBUF_SIZE,
488 "socket: %s", pcap_strerror(errno));
489 break;
490 }
491
492 fprintf( stderr,
493 "Warning: Falling back to cooked socket\n" );
494 handle->linktype = DLT_RAW;
495 }
496
497
498 device_id = iface_get_id( sock_fd, device, ebuf );
499 if( device_id == -1 )
500 break;
501
502 if( iface_bind(sock_fd, device_id, ebuf) == -1 )
503 break;
504
505 /* Select promiscous mode on/off */
506
507 /* XXX: We got reports that this does not work in 2.3.99.
508 * Need to investigate. Using ioctl to switch the promisc
509 * mode at device level costs us most of the benefits of
510 * using the new kernel interface.
511 * UPDATE: I found the bug. The kernel checks mr_alen
512 * even if it is of zero interest for the request. A
513 * random value there made the kernel return EINVAL.
514 * Probably the right solution is to memset the whole
515 * struct at first. */
516
517 memset( &mr, 0, sizeof(mr) );
518 mr.mr_ifindex = device_id;
519 mr.mr_type = promisc ?
520 PACKET_MR_PROMISC : PACKET_MR_ALLMULTI;
521 if( setsockopt( sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
522 &mr, sizeof(mr) ) == -1 )
523 {
524 snprintf(ebuf, PCAP_ERRBUF_SIZE,
525 "setsockopt: %s", pcap_strerror(errno));
526 break;
527 }
528
529 /* Compute the buffersize */
530
531 mtu = iface_get_mtu(sock_fd, device, ebuf);
532 if( mtu == -1 )
533 break;
534 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
535
536 /* Fill in the pcap structure */
537
538 handle->fd = sock_fd;
539 handle->offset = 0;
540
541 handle->buffer = malloc( handle->bufsize );
542 if( !handle->buffer ) {
543 snprintf(ebuf, PCAP_ERRBUF_SIZE,
544 "malloc: %s", pcap_strerror(errno));
545 break;
546 }
547
548 return 1;
549
550 } while(0);
551
552 if( sock_fd != -1 )
553 close( sock_fd );
554 return 0;
555 #else
556 strncpy(ebuf,
557 "New packet capturing interface not supported by build "
558 "environment", PCAP_ERRBUF_SIZE);
559 return 0;
560 #endif
561 }
562
563 #ifdef HAVE_NETPACKET_PACKET_H
564 /*
565 iface_get_id:
566
567 Return the index of the given device name. Fill ebuf and return
568 -1 on failure.
569 */
570 static int
571 iface_get_id( int fd, const char *device, char *ebuf )
572 {
573 struct ifreq ifr;
574
575 memset( &ifr, 0, sizeof(ifr) );
576 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
577
578 if( ioctl(fd, SIOCGIFINDEX, &ifr) == -1 ) {
579 snprintf(ebuf, PCAP_ERRBUF_SIZE,
580 "ioctl: %s", pcap_strerror(errno));
581 return -1;
582 }
583
584 return ifr.ifr_ifindex;
585 }
586
587 /*
588 iface_bind:
589
590 Bind the socket associated with FD to the given device.
591 */
592 static int
593 iface_bind( int fd, int ifindex, char *ebuf )
594 {
595 struct sockaddr_ll sll;
596
597 memset( &sll, 0, sizeof(sll) );
598 sll.sll_family = AF_PACKET;
599 sll.sll_ifindex = ifindex;
600 sll.sll_protocol = htons(ETH_P_ALL);
601
602 if( bind(fd, (struct sockaddr *) &sll, sizeof(sll)) == -1 ) {
603 snprintf(ebuf, PCAP_ERRBUF_SIZE,
604 "bind: %s", pcap_strerror(errno));
605 return -1;
606 }
607
608 return 0;
609 }
610
611 #endif
612
613
614 /* ===== Functions to interface to the older kernels ================== */
615
616 /* With older kernels promiscuous mode is kind of interesting because we
617 * have to reset the interface before exiting. The problem can't really
618 * be solved without some daemon taking care of managing usage counts.
619 * We save the promiscuous state of the device when opening the capture
620 * stream and arrange for it to be reset on process exit.
621 *
622 * XXX: This solution is still not correct even for this case. The
623 * devices stay in promiscuous mode until the process exits. I need to
624 * modify pcap_close to solve this. */
625
626 struct ifreq restore_ifr;
627 /* Contains the device name and the interface flags to be restored
628 * at exit */
629
630 static void restore_interface( void )
631 {
632 int status = socket(PF_INET, SOCK_PACKET, 0);
633
634 if( status != -1 )
635 status = ioctl(status, SIOCSIFFLAGS, &restore_ifr);
636
637 if( status == -1 ) {
638 fprintf(stderr,
639 "Can't restore interface flags. Please adjust manually. \n"
640 "Hint: This can't happen with Linux >= 2.2.0.\n");
641 }
642 }
643
644 /*
645 live_open_old:
646
647 Try to open a packet socket using the old kernel interface.
648 Returns 0 on failure.
649 FIXME: 0 uses to mean success (Sebastian)
650 */
651 static int
652 live_open_old( pcap_t *handle, char *device, int promisc,
653 int to_ms, char *ebuf )
654 {
655 int sock_fd = -1, mtu, arptype;
656 struct ifreq ifr;
657
658 do {
659 /* Open the socket */
660
661 sock_fd = socket( PF_INET, SOCK_PACKET, htons(ETH_P_ALL) );
662 if( sock_fd == -1 ) {
663 snprintf(ebuf, PCAP_ERRBUF_SIZE,
664 "socket: %s", pcap_strerror(errno));
665 break;
666 }
667
668 /* It worked - we are using the old interface */
669 handle->md.sock_packet = 1;
670
671 /* Bind to the given device */
672
673 if( !device ) {
674 strncpy(ebuf, "pcap_open_live: No interface given",
675 PCAP_ERRBUF_SIZE);
676 break;
677 }
678 if( iface_bind_old(sock_fd, device, ebuf) == -1 )
679 break;
680
681 /* Go to promisc mode */
682 if( promisc ) {
683 memset( &ifr, 0, sizeof(ifr) );
684 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
685 if( ioctl(sock_fd, SIOCGIFFLAGS, &ifr) == -1 ) {
686 snprintf(ebuf, PCAP_ERRBUF_SIZE,
687 "ioctl: %s", pcap_strerror(errno));
688 break;
689 }
690 if( (ifr.ifr_flags & IFF_PROMISC) == 0 ) {
691 restore_ifr = ifr;
692 ifr.ifr_flags |= IFF_PROMISC;
693 if( ioctl(sock_fd, SIOCSIFFLAGS, &ifr) == -1 ) {
694 snprintf(ebuf, PCAP_ERRBUF_SIZE,
695 "ioctl: %s",
696 pcap_strerror(errno));
697 break;
698 }
699 if( atexit(restore_interface) == -1 ) {
700 restore_interface();
701 strncpy(ebuf, "atexit failed",
702 PCAP_ERRBUF_SIZE);
703 break;
704 }
705 }
706 }
707
708
709 /* Compute the buffersize */
710
711 mtu = iface_get_mtu(sock_fd, device, ebuf);
712 if( mtu == -1 )
713 break;
714 handle->bufsize = MAX_LINKHEADER_SIZE + mtu;
715
716 /* All done - fill in the pcap handle */
717
718 arptype = iface_get_arptype(sock_fd, device, ebuf);
719 if( arptype == -1 )
720 break;
721
722 handle->fd = sock_fd;
723 handle->offset = 0;
724 handle->linktype = map_arphrd_to_dlt( arptype );
725 if( handle->linktype == -1 ) {
726 snprintf(ebuf, PCAP_ERRBUF_SIZE,
727 "interface type of %s not supported", device);
728 break;
729 }
730 handle->buffer = malloc( handle->bufsize );
731 if( !handle->buffer ) {
732 snprintf(ebuf, PCAP_ERRBUF_SIZE,
733 "malloc: %s", pcap_strerror(errno));
734 break;
735 }
736
737 return 1;
738
739 } while(0);
740
741 if( sock_fd != -1 )
742 close( sock_fd );
743 return 0;
744 }
745
746 /*
747 iface_bind_old:
748
749 Bind the socket associated with FD to the given device using the
750 interface of the old kernels.
751 */
752 static int
753 iface_bind_old( int fd, const char *device, char *ebuf )
754 {
755 struct sockaddr saddr;
756
757 memset( &saddr, 0, sizeof(saddr) );
758 strncpy( saddr.sa_data, device, sizeof(saddr.sa_data) );
759 if( bind(fd, &saddr, sizeof(saddr)) == -1 ) {
760 snprintf(ebuf, PCAP_ERRBUF_SIZE,
761 "bind: %s", pcap_strerror(errno));
762 return -1;
763 }
764
765 return 0;
766 }
767
768
769 /* ===== System calls available on all supported kernels ============== */
770
771 /*
772 iface_get_mtu:
773
774 Query the kernel for the MTU of the given interface.
775 */
776 static int
777 iface_get_mtu( int fd, const char *device, char *ebuf )
778 {
779 struct ifreq ifr;
780
781 memset( &ifr, 0, sizeof(ifr) );
782 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
783
784 if( ioctl(fd, SIOCGIFMTU, &ifr) == -1 ) {
785 snprintf(ebuf, PCAP_ERRBUF_SIZE,
786 "ioctl: %s", pcap_strerror(errno));
787 return -1;
788 }
789
790 return ifr.ifr_mtu;
791 }
792
793 /*
794 iface_get_arptype:
795
796 Get the hardware type of the given interface as ARPHRD_xxx constant.
797 */
798 static int
799 iface_get_arptype( int fd, const char *device, char *ebuf )
800 {
801 struct ifreq ifr;
802
803 memset( &ifr, 0, sizeof(ifr) );
804 strncpy( ifr.ifr_name, device, sizeof(ifr.ifr_name) );
805
806 if( ioctl(fd, SIOCGIFHWADDR, &ifr) == -1 ) {
807 snprintf(ebuf, PCAP_ERRBUF_SIZE,
808 "ioctl: %s", pcap_strerror(errno));
809 return -1;
810 }
811
812 return ifr.ifr_hwaddr.sa_family;
813 }
814