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