1
/*
2
 * interface.c -- implements fetchmail 'interface' and 'monitor' commands
3
 *
4
 * This module was implemented by George M. Sipe <gsipe@pobox.com>
5
 * or <gsipe@acm.org> and is:
6
 *
7
 *	Copyright (c) 1996,1997 by George M. Sipe
8
 *
9
 *      FreeBSD specific portions written by and Copyright (c) 1999 
10
 *      Andy Doran <ad@psn.ie>.
11
 *
12
 * For license terms, see the file COPYING in this directory.
13
 */
14
15
#include "fetchmail.h"
16
#ifdef CAN_MONITOR
17
18
#include <sys/types.h>
19
#include <sys/param.h>
20
21
#if defined(linux)
22
#include <sys/utsname.h>
23
#endif
24
25
#include <stdio.h>
26
#include <string.h>
27
#if defined(STDC_HEADERS)
28
#include <stdlib.h>
29
#endif
30
#if defined(HAVE_UNISTD_H)
31
#include <unistd.h>
32
#endif
33
#include <sys/ioctl.h>
34
#include <sys/socket.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
37
#include <net/if.h>
38
#if defined(__FreeBSD__)
39
#if defined __FreeBSD_USE_KVM
40
#if __FreeBSD_version >= 300001
41
#include <net/if_var.h>
42
#endif
43
#include <kvm.h>
44
#include <nlist.h>
45
#include <sys/fcntl.h>
46
#else
47
#include <sys/sysctl.h>
48
#include <net/route.h>
49
#include <net/if_dl.h>
50
#endif
51
#endif
52
#include "socket.h"
53
#include "i18n.h"
54
#include "tunable.h"
55
56
typedef struct {
57
	struct in_addr addr, dstaddr, netmask;
58
	int rx_packets, tx_packets;
59
} ifinfo_t;
60
61
struct interface_pair_s {
62
	struct in_addr interface_address;
63
	struct in_addr interface_mask;
64
} *interface_pair;
65
66
/*
67
 * Count of packets to see on an interface before monitor considers it up.
68
 * Needed because when pppd shuts down the link, the packet counts go up
69
 * by two (one rx and one tx?, maybe).  A value of 2 seems to do the trick,
70
 * but we'll give it some extra.
71
 */
72
#define MONITOR_SLOP		5
73
74
#ifdef linux
75
#define have_interface_init
76
77
static const char *netdevfmt;
78
79
void interface_init(void)
80
/* figure out which /proc/net/dev format to use */
81
{
82
    struct utsname utsname;
83
84
    /* Linux 2.2 -- transmit packet count in 10th field */
85
    netdevfmt = "%d %d %*d %*d %*d %d %*d %*d %*d %d %*d %*d %d";
86
87
    if (uname(&utsname) < 0)
88
        return;
89
    else
90
    {
91
	int major, minor;
92
93
	if (sscanf(utsname.release, "%d.%d.%*d", &major, &minor) >= 2
94
					&& (major < 2 || (major == 2 && minor < 2)))
95
	    /* pre-linux-2.2 format -- transmit packet count in 8th field */
96
	    netdevfmt = "%d %d %*d %*d %*d %d %*d %d %*d %*d %*d %*d %d";
97
    }
98
}
99
100
static int _get_ifinfoGT_(int socket_fd, FILE *stats_file, const char *ifname,
101
		ifinfo_t *ifinfo)
102
/* get active network interface information - return non-zero upon success */
103
{
104
	int namelen = strlen(ifname);
105
	struct ifreq request;
106
	char *cp, buffer[256];
107
	int found = 0;
108
	int counts[4];
109
110
	/* initialize result */
111
	memset((char *) ifinfo, 0, sizeof(ifinfo_t));
112
113
	/* get the packet I/O counts */
114
	while (fgets(buffer, sizeof(buffer) - 1, stats_file)) {
115
		for (cp = buffer; *cp && *cp == ' '; ++cp);
116
		if (!strncmp(cp, ifname, namelen) &&
117
				cp[namelen] == ':') {
118
			cp += namelen + 1;
119
			if (sscanf(cp, netdevfmt,
120
				   counts, counts+1, counts+2, 
121
				   counts+3,&found)>4) { /* found = dummy */
122
			        /* newer kernel with byte counts */
123
			        ifinfo->rx_packets=counts[1];
124
			        ifinfo->tx_packets=counts[3];
125
			} else {
126
			        /* older kernel, no byte counts */
127
			        ifinfo->rx_packets=counts[0];
128
			        ifinfo->tx_packets=counts[2];
129
			}
130
                        found = 1;
131
		}
132
	}
133
        if (!found) return (FALSE);
134
135
	/* see if the interface is up */
136
	strcpy(request.ifr_name, ifname);
137
	if (ioctl(socket_fd, SIOCGIFFLAGS, &request) < 0)
138
		return(FALSE);
139
	if (!(request.ifr_flags & IFF_RUNNING))
140
		return(FALSE);
141
142
	/* get the (local) IP address */
143
	strcpy(request.ifr_name, ifname);
144
	if (ioctl(socket_fd, SIOCGIFADDR, &request) < 0)
145
		return(FALSE);
146
	ifinfo->addr = ((struct sockaddr_in *) (&request.ifr_addr))->sin_addr;
147
148
	/* get the PPP destination (remote) IP address */
149
	ifinfo->dstaddr.s_addr = 0;
150
	strcpy(request.ifr_name, ifname);
151
	if (ioctl(socket_fd, SIOCGIFDSTADDR, &request) >= 0)
152
		ifinfo->dstaddr = ((struct sockaddr_in *)
153
					(&request.ifr_dstaddr))->sin_addr;
154
155
	/* get the netmask */
156
	strcpy(request.ifr_name, ifname);
157
	if (ioctl(socket_fd, SIOCGIFNETMASK, &request) >= 0) {
158
          ifinfo->netmask = ((struct sockaddr_in *)
159
                             (&request.ifr_netmask))->sin_addr;
160
          return (TRUE);
161
        }
162
163
	return(FALSE);
164
}
165
166
static int get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
167
{
168
	int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
169
	FILE *stats_file = fopen("/proc/net/dev", "r");
170
	int result;
171
172
	if (socket_fd < 0 || !stats_file)
173
		result = FALSE;
174
	else
175
	{
176
	    char *tmp = xstrdup(ifname);
177
	    char *sp = strchr(tmp, '/');
178
	    /* hide slash and trailing info from ifname */
179
	    if (sp)
180
		*sp = '\0';
181
	    result = _get_ifinfoGT_(socket_fd, stats_file, tmp, ifinfo);
182
	    free(tmp);
183
	}
184
	if (socket_fd >= 0)
185
	    SockClose(socket_fd);
186
	if (stats_file)
187
	    fclose(stats_file);	/* not checking should be safe, mode was "r" */
188
	return(result);
189
}
190
191
#elif defined __FreeBSD__
192
193
#if defined __FreeBSD_USE_KVM
194
195
static kvm_t *kvmfd;
196
static struct nlist symbols[] = 
197
{
198
	{"_ifnet"},
199
	{NULL}
200
};
201
static u_long	ifnet_savedaddr;
202
static gid_t	if_rgid;
203
static gid_t	if_egid;
204
205
void 
206
interface_set_gids(gid_t egid, gid_t rgid)
207
{
208
	if_rgid = rgid;
209
	if_egid = egid;
210
}
211
212
static int 
213
openkvm(void)
214
{
215
	if ((kvmfd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
216
		return FALSE;
217
	
218
	if (kvm_nlist(kvmfd, symbols) < 0)
219
		return FALSE;
220
	   
221
	if (kvm_read(kvmfd, (unsigned long) symbols[0].n_value, &ifnet_savedaddr, sizeof(unsigned long)) == -1)
222
		return FALSE;
223
		
224
	return TRUE;
225
}
226
227
static int 
228
get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
229
{
230
	char			tname[16];
231
	char			iname[16];
232
	struct ifnet		ifnet;
233
	unsigned long   	ifnet_addr = ifnet_savedaddr;
234
#if __FreeBSD_version >= 300001
235
	struct ifnethead	ifnethead;
236
	struct ifaddrhead	ifaddrhead;
237
#endif
238
	struct ifaddr		ifaddr;
239
	unsigned long		ifaddr_addr;
240
	struct sockaddr		sa;
241
	unsigned long		sa_addr;
242
	uint			i;
243
	
244
	if (if_egid)
245
		setegid(if_egid);
246
	
247
	for (i = 0; ifname[i] && ifname[i] != '/' && i < sizeof(iname) - 1; i++)
248
		iname[i] = ifname[i];
249
		
250
	iname[i] = '\0';
251
	
252
	if (!kvmfd)
253
	{
254
		if (!openkvm())
255
		{
256
			report(stderr, 0, GT_("Unable to open kvm interface. Make sure fetchmail is SGID kmem."));
257
			if (if_egid)
258
				setegid(if_rgid);
259
			exit(1);
260
		}
261
	}
262
263
#if __FreeBSD_version >= 300001
264
	kvm_read(kvmfd, ifnet_savedaddr, (char *) &ifnethead, sizeof ifnethead);
265
	ifnet_addr = (u_long) ifnethead.tqh_first;
266
#else
267
	ifnet_addr = ifnet_savedaddr;
268
#endif
269
270
	while (ifnet_addr)
271
	{
272
		kvm_read(kvmfd, ifnet_addr, &ifnet, sizeof(ifnet));
273
		kvm_read(kvmfd, (unsigned long) ifnet.if_name, tname, sizeof tname);
274
		snprintf(tname + strlen(tname), sizeof(tname) - strlen(tname), "%d", ifnet.if_unit);
275
276
		if (!strcmp(tname, iname))
277
		{
278
			if (!(ifnet.if_flags & IFF_UP))
279
			{
280
				if (if_egid)
281
					setegid(if_rgid);
282
				return 0;
283
			}
284
				
285
			ifinfo->rx_packets = ifnet.if_ipackets;
286
			ifinfo->tx_packets = ifnet.if_opackets;
287
288
#if __FreeBSD_version >= 300001
289
			ifaddr_addr = (u_long) ifnet.if_addrhead.tqh_first;
290
#else
291
			ifaddr_addr = (u_long) ifnet.if_addrlist;
292
#endif
293
			
294
			while(ifaddr_addr)
295
			{
296
				kvm_read(kvmfd, ifaddr_addr, &ifaddr, sizeof(ifaddr));
297
				kvm_read(kvmfd, (u_long)ifaddr.ifa_addr, &sa, sizeof(sa));
298
				
299
				if (sa.sa_family != AF_INET)
300
				{
301
#if __FreeBSD_version >= 300001
302
					ifaddr_addr = (u_long) ifaddr.ifa_link.tqe_next;
303
#else
304
					ifaddr_addr = (u_long) ifaddr.ifa_next;
305
#endif
306
					continue;
307
				}
308
			
309
				ifinfo->addr.s_addr = *(u_long *)(sa.sa_data + 2);
310
				kvm_read(kvmfd, (u_long)ifaddr.ifa_dstaddr, &sa, sizeof(sa));
311
				ifinfo->dstaddr.s_addr = *(u_long *)(sa.sa_data + 2);
312
				kvm_read(kvmfd, (u_long)ifaddr.ifa_netmask, &sa, sizeof(sa));
313
				ifinfo->netmask.s_addr = *(u_long *)(sa.sa_data + 2);
314
315
				if (if_egid)
316
					setegid(if_rgid);
317
318
				return 1;
319
			}
320
			
321
			if (if_egid)
322
				setegid(if_rgid);
323
			
324
			return 0;
325
		}
326
327
#if __FreeBSD_version >= 300001
328
		ifnet_addr = (u_long) ifnet.if_link.tqe_next;
329
#else
330
		ifnet_addr = (unsigned long) ifnet.if_next;
331
#endif
332
	}
333
334
	if (if_egid)
335
		setegid(if_rgid);
336
	
337
	return 0;
338
}
339
340
#else /* Do not use KVM on FreeBSD */
341
342
/*
343
 * Expand the compacted form of addresses as returned via the
344
 * configuration read via sysctl().
345
 */
346
347
static void
348
rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
349
{
350
    struct sockaddr *sa;
351
    int i;
352
353
#define ROUNDUP(a) \
354
	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
355
#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
356
357
    memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
358
    for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
359
	if ((rtinfo->rti_addrs & (1 << i)) == 0)
360
	    continue;
361
	rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
362
	ADVANCE(cp, sa);
363
    }
364
365
#undef ROUNDUP
366
#undef ADVANCE
367
}
368
369
static int
370
get_ifinfo(const char *ifname, ifinfo_t *ifinfo)
371
{
372
    uint		i;
373
    int			rc = 0;
374
    int			ifindex = -1;
375
    size_t		needed;
376
    char		*buf = NULL;
377
    char		*lim = NULL;
378
    char		*next = NULL;
379
    struct if_msghdr 	*ifm;
380
    struct ifa_msghdr 	*ifam;
381
    struct sockaddr_in 	*sin;
382
    struct sockaddr_dl 	*sdl;
383
    struct rt_addrinfo 	info;
384
    char		iname[16];
385
    int			mib[6];
386
387
    memset(ifinfo, 0, sizeof(ifinfo));
388
389
    /* trim interface name */
390
391
    for (i = 0; i < sizeof(iname) && ifname[i] && ifname[i] != '/'; i++)
392
	iname[i] = ifname[i];
393
	
394
    if (i == 0 || i == sizeof(iname))
395
    {
396
	report(stderr, GT_("Unable to parse interface name from %s"), ifname);
397
	return 0;
398
    }
399
400
    iname[i] = 0;
401
402
403
    /* get list of existing interfaces */
404
405
    mib[0] = CTL_NET;
406
    mib[1] = PF_ROUTE;
407
    mib[2] = 0;
408
    mib[3] = AF_INET;		/* Only IP addresses please. */
409
    mib[4] = NET_RT_IFLIST;
410
    mib[5] = 0;			/* List all interfaces. */
411
412
413
    /* Get interface data. */
414
415
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
416
    {
417
 	report(stderr, 
418
	    GT_("get_ifinfo: sysctl (iflist estimate) failed"));
419
	exit(1);
420
    }
421
    if ((buf = (char *)malloc(needed)) == NULL)
422
    {
423
 	report(stderr, 
424
	    GT_("get_ifinfo: malloc failed"));
425
	exit(1);
426
    }
427
    if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
428
    {
429
 	report(stderr, 
430
	    GT_("get_ifinfo: sysctl (iflist) failed"));
431
	exit(1);
432
    }
433
434
    lim = buf+needed;
435
436
437
    /* first look for the interface information */
438
439
    next = buf;
440
    while (next < lim)
441
    {
442
	ifm = (struct if_msghdr *)next;
443
	next += ifm->ifm_msglen;
444
445
	if (ifm->ifm_version != RTM_VERSION) 
446
	{
447
 	    report(stderr, 
448
		GT_("Routing message version %d not understood."),
449
		ifm->ifm_version);
450
	    exit(1);
451
	}
452
453
	if (ifm->ifm_type == RTM_IFINFO)
454
	{
455
	    sdl = (struct sockaddr_dl *)(ifm + 1);
456
457
	    if (!(strlen(iname) == sdl->sdl_nlen 
458
		&& strncmp(iname, sdl->sdl_data, sdl->sdl_nlen) == 0))
459
	    {
460
		continue;
461
	    }
462
463
	    if ( !(ifm->ifm_flags & IFF_UP) )
464
	    {
465
		/* the interface is down */
466
		goto get_ifinfo_end;
467
	    }
468
469
	    ifindex = ifm->ifm_index;
470
	    ifinfo->rx_packets = ifm->ifm_data.ifi_ipackets;
471
	    ifinfo->tx_packets = ifm->ifm_data.ifi_opackets;
472
473
	    break;
474
	}
475
    }
476
477
    if (ifindex < 0)
478
    {
479
	/* we did not find an interface with a matching name */
480
	report(stderr, GT_("No interface found with name %s"), iname);
481
	goto get_ifinfo_end;
482
    }
483
484
    /* now look for the interface's IP address */
485
486
    next = buf;
487
    while (next < lim)
488
    {
489
	ifam = (struct ifa_msghdr *)next;
490
	next += ifam->ifam_msglen;
491
492
	if (ifindex > 0
493
	    && ifam->ifam_type == RTM_NEWADDR
494
	    && ifam->ifam_index == ifindex)
495
	{
496
	    /* Expand the compacted addresses */
497
	    info.rti_addrs = ifam->ifam_addrs;
498
	    rt_xaddrs((char *)(ifam + 1), 
499
			ifam->ifam_msglen + (char *)ifam,
500
	  		&info);
501
502
	    /* Check for IPv4 address information only */
503
	    if (info.rti_info[RTAX_IFA]->sa_family != AF_INET)
504
	    {
505
		continue;
506
	    }
507
508
	    rc = 1;
509
510
	    sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
511
	    if (sin)
512
	    {
513
		ifinfo->addr = sin->sin_addr;
514
	    }
515
516
	    sin = (struct sockaddr_in *)info.rti_info[RTAX_NETMASK];
517
	    if (sin)
518
	    {
519
		ifinfo->netmask = sin->sin_addr;
520
	    }
521
522
	    /* note: RTAX_BRD contains the address at the other
523
	     * end of a point-to-point link or the broadcast address
524
	     * of non point-to-point link
525
	     */
526
	    sin = (struct sockaddr_in *)info.rti_info[RTAX_BRD];
527
	    if (sin)
528
	    {
529
		ifinfo->dstaddr = sin->sin_addr;
530
	    }
531
532
	    break;
533
	}
534
    }
535
536
    if (rc == 0)
537
    {
538
	report(stderr, GT_("No IP address found for %s"), iname);
539
    }
540
541
get_ifinfo_end:
542
    free(buf);
543
    return rc;
544
}
545
546
#endif /* __FREEBSD_USE_SYSCTL_GET_IFFINFO */
547
548
#endif
549
550
#ifndef HAVE_INET_ATON
551
/*
552
 * Note: This is not a true replacement for inet_aton(), as it won't
553
 * do the right thing on "255.255.255.255" (which translates to -1 on
554
 * most machines).  Fortunately this code will be used only if you're
555
 * on an older Linux that lacks a real implementation.
556
 */
557
#ifdef HAVE_NETINET_IN_SYSTM_H
558
# include <sys/types.h>
559
# include <netinet/in_systm.h>
560
#endif
561
562
#include <netinet/in.h>
563
#include <netinet/ip.h>
564
#include <arpa/inet.h>
565
#include <string.h>
566
567
static int inet_aton(const char *cp, struct in_addr *inp) {
568
    long addr;
569
570
    addr = inet_addr(cp);
571
    if (addr == ((long) -1)) return 0;
572
573
    memcpy(inp, &addr, sizeof(addr));
574
    return 1;
575
}
576
#endif /* HAVE_INET_ATON */
577
578
void interface_parse(char *buf, struct hostdata *hp)
579
/* parse 'interface' specification */
580
{
581
	char *cp1, *cp2;
582
	char mask1[] = "255.255.255.255";
583
584
	hp->interface = xstrdup(buf);
585
586
	/* find and isolate just the IP address */
587
	if (!(cp1 = strchr(buf, '/')))
588
	{
589
		(void) report(stderr,
590
			      GT_("missing IP interface address\n"));
591
		exit(PS_SYNTAX);
592
	}
593
	*cp1++ = '\000';
594
595
	/* find and isolate just the netmask */
596
	if (!(cp2 = strchr(cp1, '/')))
597
		cp2 = mask1;
598
	else
599
		*cp2++ = '\000';
600
601
	/* convert IP address and netmask */
602
	hp->interface_pair = (struct interface_pair_s *)xmalloc(sizeof(struct interface_pair_s));
603
	if (!inet_aton(cp1, &hp->interface_pair->interface_address))
604
	{
605
		(void) report(stderr,
606
			      GT_("invalid IP interface address\n"));
607
		exit(PS_SYNTAX);
608
	}
609
	if (!inet_aton(cp2, &hp->interface_pair->interface_mask))
610
	{
611
		(void) report(stderr,
612
			      GT_("invalid IP interface mask\n"));
613
		exit(PS_SYNTAX);
614
	}
615
	/* apply the mask now to the IP address (range) required */
616
	hp->interface_pair->interface_address.s_addr &=
617
		hp->interface_pair->interface_mask.s_addr;
618
619
	/* restore original interface string (for configuration dumper) */
620
	*--cp1 = '/';
621
	return;
622
}
623
624
void interface_note_activity(struct hostdata *hp)
625
/* save interface I/O counts */
626
{
627
	ifinfo_t ifinfo;
628
	struct query *ctl;
629
630
	/* if not monitoring link, all done */
631
	if (!hp->monitor)
632
		return;
633
634
	/* get the current I/O stats for the monitored link */
635
	if (get_ifinfo(hp->monitor, &ifinfo))
636
		/* update this and preceeding host entries using the link
637
		   (they were already set during this pass but the I/O
638
		   count has now changed and they need to be re-updated)
639
		*/
640
		for (ctl = querylist; ctl; ctl = ctl->next) {
641
			if (ctl->server.monitor && !strcmp(hp->monitor, ctl->server.monitor))
642
				ctl->server.monitor_io =
643
					ifinfo.rx_packets + ifinfo.tx_packets;
644
			/* do NOT update host entries following this one */
645
			if (&ctl->server == hp)
646
				break;
647
		}
648
649
#ifdef	ACTIVITY_DEBUG
650
	(void) report(stdout, 
651
		      GT_("activity on %s -noted- as %d\n"), 
652
		      hp->monitor, hp->monitor_io);
653
#endif
654
}
655
656
int interface_approve(struct hostdata *hp, flag domonitor)
657
/* return TRUE if OK to poll, FALSE otherwise */
658
{
659
	ifinfo_t ifinfo;
660
661
	/* check interface IP address (range), if specified */
662
	if (hp->interface) {
663
		/* get interface info */
664
		if (!get_ifinfo(hp->interface, &ifinfo)) {
665
			(void) report(stdout, 
666
				      GT_("skipping poll of %s, %s down\n"),
667
				      hp->pollname, hp->interface);
668
			return(FALSE);
669
		}
670
		/* check the IP addresses (range) */
671
		if	(!(
672
				/* check remote IP address */
673
				((ifinfo.dstaddr.s_addr != 0) &&
674
				(ifinfo.dstaddr.s_addr &
675
				hp->interface_pair->interface_mask.s_addr) ==
676
				hp->interface_pair->interface_address.s_addr)
677
				||
678
				/* check local IP address */
679
				((ifinfo.addr.s_addr &
680
				hp->interface_pair->interface_mask.s_addr) ==
681
				hp->interface_pair->interface_address.s_addr)
682
			) )
683
		{
684
			(void) report(stdout,
685
				GT_("skipping poll of %s, %s IP address excluded\n"),
686
				hp->pollname, hp->interface);
687
			return(FALSE);
688
		}
689
	}
690
691
	/* if not monitoring link, all done */
692
	if (!domonitor || !hp->monitor)
693
		return(TRUE);
694
695
#ifdef	ACTIVITY_DEBUG
696
	(void) report(stdout, 
697
		      GT_("activity on %s checked as %d\n"), 
698
		      hp->monitor, hp->monitor_io);
699
#endif
700
	/* if monitoring, check link for activity if it is up */
701
	if (get_ifinfo(hp->monitor, &ifinfo))
702
	{
703
	    int diff = (ifinfo.rx_packets + ifinfo.tx_packets)
704
							- hp->monitor_io;
705
706
	    /*
707
	     * There are three cases here:
708
	     *
709
	     * (a) If the new packet count is less than the recorded one,
710
	     * probably pppd was restarted while fetchmail was running.
711
	     * Don't skip.
712
	     *
713
	     * (b) newpacket count is greater than the old packet count,
714
	     * but the difference is small and may just reflect the overhead
715
	     * of a link shutdown.  Skip.
716
	     *
717
	     * (c) newpacket count is greater than the old packet count,
718
	     * and the difference is large. Connection is live.  Don't skip.
719
	     */
720
	    if (diff >= 0 && diff <= MONITOR_SLOP)
721
	    {
722
		(void) report(stdout, 
723
			      GT_("skipping poll of %s, %s inactive\n"),
724
			      hp->pollname, hp->monitor);
725
		return(FALSE);
726
	    }
727
	}
728
729
#ifdef ACTIVITY_DEBUG
730
       report(stdout, GT_("activity on %s was %d, is %d\n"),
731
             hp->monitor, hp->monitor_io,
732
             ifinfo.rx_packets + ifinfo.tx_packets);
733
#endif
734
735
	return(TRUE);
736
}
737
#endif /* CAN_MONITOR */
738
739
#ifndef have_interface_init
740
void interface_init(void) {}
741
#endif