#ifndef lint static char *RCSid = "$Header: /proj/freeware1.0/nfswatch/nfswatch4.1/RCS/nfswatch.c,v 1.1 1995/08/08 04:40:36 rck Exp $"; #endif #include "os.h" /* * nfswatch - NFS server packet monitoring program. * * David A. Curry Jeffrey C. Mogul * Purdue University Digital Equipment Corporation * Engineering Computer Network Western Research Laboratory * 1285 Electrical Engineering Building 250 University Avenue * West Lafayette, IN 47907-1285 Palo Alto, CA 94301 * davy@ecn.purdue.edu mogul@decwrl.dec.com * * $Log: nfswatch.c,v $ * Revision 1.1 1995/08/08 04:40:36 rck * initial checkin * * Revision 4.3 93/10/04 11:01:12 mogul * Added support for "-fhdebug" * * Revision 4.2 93/09/28 21:25:29 mogul * Explicit data type for IP addresses * * Revision 4.1 93/09/15 20:30:15 davy * Added Sun FDDI/S interfaces. * * Revision 4.0 1993/03/01 19:59:00 davy * NFSWATCH Version 4.0. * * Revision 3.13 1993/02/24 17:44:45 davy * Added -auth mode, changes to -proc mode, -map option, -server option. * * Revision 3.12 1993/01/20 14:52:30 davy * Added -T maxtime option. * * Revision 3.11 1993/01/16 19:08:59 davy * Corrected Jeff's address. * * Revision 3.10 1993/01/15 22:09:20 davy * Fixed for Sun FDDI using the NIT. * * Revision 3.9 1993/01/15 19:33:39 davy * Miscellaneous cleanups. * * Revision 3.8 1993/01/15 15:43:36 davy * Assorted changes for porting to Solaris 2.x/SVR4. * * Revision 3.7 1993/01/14 15:51:16 davy * Added FDDI code and device type calculation to NIT and SNOOP. The FDDI * stuff almost definitely won't work without modification on the SNOOP * side; it still needs to be tested on the NIT side. * * Revision 3.6 1993/01/13 21:24:19 davy * Assorted changes for porting to IRIX. * * Revision 3.5 1993/01/13 20:18:17 davy * Put in OS-specific define scheme, and merged in Tim Hudson's code for * SGI systems (as yet untested). * * Revision 3.4 1993/01/13 18:59:30 davy * Changed sigvec calls to signal calls, for portability to other os versions. * * Revision 3.3 1993/01/13 15:12:05 davy * Added background mode. * * Revision 3.2 1992/07/24 18:47:57 mogul * Added FDDI support * * Revision 3.1 1991/01/23 16:56:19 mogul * Black magic * * Revision 3.1 1991/01/23 16:56:19 mogul * Black magic * * Revision 3.0 91/01/23 08:23:11 davy * NFSWATCH Version 3.0. * * Revision 1.5 91/01/04 16:05:15 davy * Updated version number. * * Revision 1.4 91/01/04 15:54:29 davy * New features from Jeff Mogul. * * Revision 1.3 90/12/04 08:06:41 davy * Changed version number to 2.1. * * Revision 1.2 90/08/17 15:47:29 davy * NFSWATCH Version 2.0. * * Revision 1.1 88/11/29 11:20:40 davy * NFSWATCH Release 1.0 * */ #include #include #include #include #include #include #include #include #ifdef USE_DLPI #include #include #if defined(SVR4) && !defined(SUNOS5) char *devices[] = { "emd0", "emd1", "emd2", "emd3", "emd4", 0 }; #endif #ifdef SUNOS5 #include char *devices[] = { "le0", "le1", "le2", "le3", "le4", "ie0", "ie1", "ie2", "ie3", "ie4", "fddi0", "fddi1", "fddi2", "fddi3", "fddi4", 0 }; #endif #endif /* USE_DLPI */ #ifdef USE_NIT #include #include char *devices[] = { "le0", "le1", "le2", "le3", "le4", "ie0", "ie1", "ie2", "ie3", "ie4", "fddi0", "fddi1", "fddi2", "fddi3", "fddi4", "bf0", "bf1", 0 }; #endif /* USE_NIT */ #ifdef USE_PFILT #include char *devices[] = { "pf0", "pf1", "pf2", "pf3", "pf4", "pf5", "pf6", "pf7", "pf8", "pf9", 0 }; #endif /* USE_PFILT */ #ifdef USE_SNOOP #include #include #include #define ETHERHDRPAD RAW_HDRPAD(sizeof(struct ether_header)) char *devices[] = { "et0", "et1", "et2", "et3", "et4", "ec0", "ec1", "ec2", "ec3", "ec4", "fxp0", "fxp1", "fxp2", "fxp3", "fxp4", "enp0", "enp1", "enp2", "enp3", "enp4", "ipg0", "ipg1", "ipg2", "ipg3", "ipg4", 0 }; struct etherpacket { struct snoopheader snoop; char pad[ETHERHDRPAD]; struct ether_header ether; char data[ETHERMTU]; }; #endif /* USE_SNOOP */ #include "nfswatch.h" char *pname; /* program name */ FILE *logfp; /* log file pointer */ Counter pkt_total = 0; /* total packets seen */ Counter pkt_drops = 0; /* total packets dropped*/ Counter int_pkt_total = 0; /* packets this interval*/ Counter int_pkt_drops = 0; /* dropped this interval*/ Counter dst_pkt_total = 0; /* total pkts to host */ Counter int_dst_pkt_total = 0; /* pkts to host this int*/ int if_fd[MAXINTERFACES]; /* LAN device file desc */ int if_dlt[MAXINTERFACES]; /* LAN data link type */ int bgflag = 0; /* "-bg" specified */ int srcflag = 0; /* "-src" specified */ int dstflag = 0; /* "-dst" specified */ int allflag = 0; /* "-all" specified */ int allintf = 0; /* "-allif" specified */ int fhdebugf = 0; /* "-fhdebug" specified */ int logging = 0; /* 1 when logging on */ int learnfs = 0; /* learn other servers */ int do_update = 0; /* time to update screen*/ int showwhich = 0; /* show filesys or files*/ int serverflag = 0; /* "-server" specified */ int cycletime = CYCLETIME; /* update cycle time */ int totaltime = 0; /* total run time */ int truncation = 200; /* pkt trunc len - magic*/ int sortbyusage = 0; /* sort by usage counts */ int nnfscounters = 0; /* # of NFS counters */ int nfilecounters = 0; /* # of file counters */ int nauthcounters = 0; /* # of auth counters */ int nclientcounters = 0; /* # of client counters */ int screen_inited = 0; /* 1 when in curses */ struct timeval starttime; /* time we started */ int ninterfaces; /* number of interfaces */ ipaddrt thisdst = 0; /* cached IP dst of pkt */ ipaddrt srcaddrs[MAXHOSTADDR]; /* src host net addrs */ ipaddrt dstaddrs[MAXHOSTADDR]; /* dst host net addrs */ ipaddrt serveraddrs[MAXHOSTADDR]; /* server host net addrs*/ char myhost[MAXHOSTNAMELEN]; /* local host name */ char srchost[MAXHOSTNAMELEN]; /* source host name */ char dsthost[MAXHOSTNAMELEN]; /* destination host name*/ char serverhost[MAXHOSTNAMELEN]; /* server host name */ char *prompt = PROMPT; /* prompt string */ char *filelist = NULL; /* list of files */ char *logfile = LOGFILE; /* log file name */ char *mapfile = NULL; /* map file name */ char *snapshotfile = SNAPSHOTFILE; /* snapshot file name */ NFSCounter nfs_counters[MAXEXPORT]; /* NFS request counters */ FileCounter fil_counters[MAXEXPORT]; /* file request counters*/ PacketCounter pkt_counters[PKT_NCOUNTERS]; /* packet counters */ ProcCounter prc_counters[MAXNFSPROC+2]; /* procedure counters */ /* extra space simplifies sort_prc_counters */ int prc_countmap[MAXNFSPROC]; /* allows sorting */ ClientCounter clnt_counters[MAXCLIENTS]; /* per-client counters */ AuthCounter auth_counters[MAXAUTHS]; /* per-auth counters */ extern void finish(); #ifdef ultrix void fpe_warn() { fprintf(stderr, "nfswatch: mystery bug encountered.\n"); finish(-1); } #endif main(argc, argv) int argc; char **argv; { register int i; char *device = NULL; extern void nfswatch(); pname = *argv; /* * Get our host name. The default destination * host is the one we're running on. */ if (gethostname(myhost, sizeof(myhost)) < 0) { error("gethostname"); finish(-1); } (void) strcpy(dsthost, myhost); /* * Process arguments. */ while (--argc) { if (**++argv != '-') usage(); /* * Set destination host. */ if (!strcmp(*argv, "-dst")) { if (--argc <= 0) usage(); (void) strcpy(dsthost, *++argv); dstflag++; continue; } /* * Set source host. */ if (!strcmp(*argv, "-src")) { if (--argc <= 0) usage(); (void) strcpy(srchost, *++argv); srcflag++; continue; } /* * Set server host. */ if (!strcmp(*argv, "-server")) { if (--argc <= 0) usage(); (void) strcpy(serverhost, *++argv); serverflag++; continue; } /* * Device to use. */ if (!strcmp(*argv, "-dev")) { if (--argc <= 0) usage(); device = *++argv; continue; } /* * Log file name. */ if (!strcmp(*argv, "-lf")) { if (--argc <= 0) usage(); logfile = *++argv; continue; } /* * Snapshot file name. */ if (!strcmp(*argv, "-sf")) { if (--argc <= 0) usage(); snapshotfile = *++argv; continue; } /* * List of files. */ if (!strcmp(*argv, "-f")) { if (--argc <= 0) usage(); if (showwhich == 0) showwhich = SHOWINDVFILES; filelist = *++argv; continue; } /* * Set map file. */ if (!strcmp(*argv, "-map")) { if (--argc <= 0) usage(); mapfile = *++argv; continue; } /* * Set total run time. */ if (!strcmp(*argv, "-T")) { if (--argc <= 0) usage(); totaltime = atoi(*++argv); continue; } /* * Change cycle time. */ if (!strcmp(*argv, "-t")) { if (--argc <= 0) usage(); cycletime = atoi(*++argv); continue; } /* * Show RPC authentication. */ if (!strcmp(*argv, "-auth")) { showwhich = SHOWAUTH; continue; } /* * Show file systems. */ if (!strcmp(*argv, "-fs")) { showwhich = SHOWFILESYSTEM; continue; } /* * Show individual files. */ if (!strcmp(*argv, "-if")) { showwhich = SHOWINDVFILES; continue; } /* * Show NFS procedures */ if (!strcmp(*argv, "-procs")) { showwhich = SHOWNFSPROCS; continue; } /* * Show NFS clients */ if (!strcmp(*argv, "-clients")) { showwhich = SHOWCLIENTS; continue; } /* * Turn on logging. */ if (!strcmp(*argv, "-l")) { logging++; continue; } /* * Run in background mode. */ if (!strcmp(*argv, "-bg")) { logging++; bgflag++; continue; } /* * Watch all traffic. */ if (!strcmp(*argv, "-all")) { allflag++; continue; } /* * Use all interfaces. */ if (!strcmp(*argv, "-allif")) { allintf++; continue; } /* * Sort file systems by usage, not name. */ if (!strcmp(*argv, "-usage")) { sortbyusage++; continue; } if (!strcmp(*argv, "-fhdebug")) { fhdebugf++; continue; } usage(); } /* * Check what we're showing. */ switch (showwhich) { case 0: /* default */ showwhich = SHOWFILESYSTEM; break; case SHOWINDVFILES: if (filelist == NULL) { (void) fprintf(stderr, "%s: must specify file list with -fi.\n", pname); finish(-1); } break; } /* * Trap signals so we can clean up. */ (void) signal(SIGINT, finish); (void) signal(SIGQUIT, finish); (void) signal(SIGTERM, finish); #ifdef sgi /* * Kludge to prevent coredumps when the optimizer's on? */ (void) signal(SIGFPE, SIG_IGN); #endif #ifdef ultrix (void) signal(SIGFPE, fpe_warn); #endif #ifdef USE_DLPI /* * Set up the data link interface provider right away, * since we probably need super-user permission. */ if (allintf) { ninterfaces = 0; for (i=0; devices[i] != NULL; i++) { if_fd[ninterfaces] = setup_dlpi_dev(&devices[i]); if (if_fd[ninterfaces] >= 0) { if_dlt[ninterfaces] = dlpi_devtype(if_fd[ninterfaces]); ninterfaces++; } } } else { if_fd[0] = setup_dlpi_dev(&device); if (if_fd[0] < 0) { error(device); finish(-1); } if_dlt[0] = dlpi_devtype(if_fd[0]); ninterfaces = 1; } #endif /* USE_DLPI */ #ifdef USE_NIT /* * Set up the network interface tap right away, * since we probably need super-user permission. */ if (allintf) { ninterfaces = 0; for (i=0; devices[i] != NULL; i++) { if_fd[ninterfaces] = setup_nit_dev(&devices[i]); if (if_fd[ninterfaces] >= 0) { if_dlt[ninterfaces] = nit_devtype(devices[i]); ninterfaces++; } } } else { if_fd[0] = setup_nit_dev(&device); if (if_fd[0] < 0) { error(device); finish(-1); } if_dlt[0] = nit_devtype(device); ninterfaces = 1; } #endif /* USE_NIT */ #ifdef USE_PFILT /* * Set up the packet filter interface now, * although we don't need super-user permission. */ if (allintf) { ninterfaces = 0; for (i=0; devices[i] != NULL; i++) { if_fd[ninterfaces] = setup_pfilt_dev(&devices[i]); if (if_fd[ninterfaces] >= 0) { if_dlt[ninterfaces] = pfilt_devtype(if_fd[ninterfaces]); ninterfaces++; } } } else { if_fd[0] = setup_pfilt_dev(&device); if (if_fd[0] < 0) { error(device); finish(-1); } if_dlt[0] = pfilt_devtype(if_fd[0]); ninterfaces = 1; } #endif /* USE_PFILT */ #ifdef USE_SNOOP /* * Set up the snoop interface right away, * since we probably need super-user permission. */ if (allintf) { ninterfaces = 0; for (i=0; devices[i] != NULL; i++) { if_fd[ninterfaces] = setup_snoop_dev(&devices[i]); if (if_fd[ninterfaces] >= 0) { if_dlt[ninterfaces] = snoop_devtype(devices[i]); ninterfaces++; } } } else { if_fd[0] = setup_snoop_dev(&device); if (if_fd[0] < 0) { error(device); finish(-1); } if_dlt[0] = snoop_devtype(device); ninterfaces = 1; } #endif /* USE_SNOOP */ if (ninterfaces < 1) { fprintf(stderr, "%s: no valid interfaces.\n", pname); finish(-1); } /* * Now lose super-user permission, since we * don't need it for anything else. */ #ifdef SVR4 (void) setuid(getuid()); (void) seteuid(getuid()); #else (void) setreuid(getuid(), getuid()); #endif /* * Look up the network addresses of the source and * destination hosts. */ get_net_addrs(); /* * Tell the user what's going on. */ (void) printf("NFSWATCH Version %s\n", VERSION); if (serverflag) { (void) printf("Watch packets to/from %s on ", serverhost); } else { (void) printf("Watch packets from %s to %s on ", (srcflag ? srchost : "all hosts"), dsthost); } if (allintf) (void) printf("all interfaces;\n"); else { (void) printf("%s ", dlt_name(if_dlt[0])); (void) printf("interface %s;\n", device); } (void) printf("log to \"%s\" (logging %s);\n", logfile, (logging ? "on" : "off")); if (bgflag) { (void) printf("cycle time %d seconds;\n", cycletime); (void) printf("running as a daemon in the background..."); } else { (void) printf("snapshots to \"%s\";\n", snapshotfile); (void) printf("cycle time %d seconds...", cycletime); } (void) fflush(stdout); /* * No more informational output, so fork and exit if in * background mode. */ if (bgflag) { int pid; if ((pid = fork()) < 0) { error("fork"); finish(-1); } if (pid != 0) { printf("pid = %d\n", pid); exit(0); } } if (fhdebugf) { /* Don't fork a daemon, but also don't update the screen */ bgflag++; (void) printf("\n"); (void) fflush(stdin); } /* * Set up a pseudo RPC server. */ setup_rpcxdr(); /* * Set up the screen. */ if (!bgflag) setup_screen(device); /* * Set up the packet counters. This must be done after * setup_screen because they use the LINES variable. */ setup_pkt_counters(); setup_nfs_counters(); setup_proc_counters(); if (filelist) setup_fil_counters(); if (mapfile) setup_map_file(); /* * Now label the screen. */ if (!bgflag) label_screen(); /* * Open log file if logging is on. */ if (logging) { if ((logfp = fopen(logfile, "a")) == NULL) { error(logfile); finish(-1); } (void) fprintf(logfp, "#\n# startlog\n#\n"); (void) fprintf(logfp, "# NFSwatch log file\n"); (void) fprintf(logfp, "# Packets from: %s\n", (srcflag ? srchost : "all hosts")); (void) fprintf(logfp, "# Packets to: %s\n#\n", dsthost); } /* * Go watch packets. Never returns. */ nfswatch(); } /* * nfswatch - main packet reading loop. */ void nfswatch() { int i, cc; char *buf; char *malloc(); fd_set readfds; struct timeval tv; extern void wakeup(); struct itimerval itv; register char *bp, *cp, *bufstop; #ifdef USE_DLPI int tdrops[MAXINTERFACES]; struct strbuf strdata; struct sb_hdr *hdrp; int flags; #endif #ifdef USE_NIT int tdrops[MAXINTERFACES]; struct nit_iftime *tstamp; struct nit_bufhdr *hdrp; struct nit_ifdrops *ndp; #endif #ifdef USE_PFILT struct enstamp stamp; int datalen; #endif #ifdef USE_SNOOP int tdrops[MAXINTERFACES]; struct etherpacket ep; struct rawstats rs; #endif #ifdef USE_DLPI /* * Allocate a buffer so it's properly aligned for * casting to structure types. */ if ((buf = malloc(DLPI_CHUNKSIZE)) == NULL) { (void) fprintf(stderr, "%s: out of memory.\n", pname); finish(-1); } strdata.len = 0; strdata.buf = buf; strdata.maxlen = DLPI_CHUNKSIZE; #endif #ifdef USE_NIT /* * Allocate a buffer so it's properly aligned for * casting to structure types. */ if ((buf = malloc(NIT_CHUNKSIZE)) == NULL) { (void) fprintf(stderr, "%s: out of memory.\n", pname); finish(-1); } #endif #ifdef USE_PFILT /* * Allocate a buffer so it's properly aligned for * casting to structure types. */ if ((buf = malloc(PFILT_CHUNKSIZE)) == NULL) { (void) fprintf(stderr, "%s: out of memory.\n", pname); finish(-1); } #endif /* * Set up the alarm handler. */ (void) signal(SIGALRM, wakeup); /* * Set up the alarm clock. */ (void) bzero((char *) &itv, sizeof(struct itimerval)); itv.it_interval.tv_sec = cycletime; itv.it_interval.tv_usec = 0; itv.it_value = itv.it_interval; (void) setitimer(ITIMER_REAL, &itv, (struct itimerval *) 0); /* * Set the start time. */ (void) gettimeofday(&starttime, (struct timezone *) 0); #ifdef USE_DLPI /* * Flush the read queue of any packets that accumulated * during setup time. */ for (i=0; i < ninterfaces; i++) { flush_dlpi(if_fd[i]); tdrops[i] = 0; } for (;;) { FD_ZERO(&readfds); for (i=0; i < ninterfaces; i++) FD_SET(if_fd[i], &readfds); /* * See which nets have packets to read. */ cc = select(NFDBITS, &readfds, (fd_set *) 0, (fd_set *) 0, 0); if ((cc < 0) && (errno != EINTR)) { error("select"); finish(-1); } if (cc == 0) { continue; } /* * For each interface... */ for (i=0; i < ninterfaces; i++) { /* * Nothing to read. */ if (!FD_ISSET(if_fd[i], &readfds)) continue; /* * Now read packets from the dlpi device. */ flags = 0; strdata.len = 0; if (getmsg(if_fd[i], NULL, &strdata, &flags) != 0) continue; bufstop = buf + strdata.len; bp = buf; #ifdef SUNOS5 /* * Loop through the chunk, extracting packets. */ while (bp < bufstop) { cp = bp; /* * Get the nit header. */ hdrp = (struct sb_hdr *) cp; cp += sizeof(struct sb_hdr); int_pkt_drops += hdrp->sbh_drops - tdrops[i]; pkt_drops += hdrp->sbh_drops - tdrops[i]; tdrops[i] = hdrp->sbh_drops; /* * Filter the packet. */ if (if_dlt[i] == DLT_FDDI) { pkt_filter_fddi(cp, hdrp->sbh_msglen, &hdrp->sbh_timestamp); } else { pkt_filter_ether(cp, hdrp->sbh_msglen, &hdrp->sbh_timestamp); } /* * Skip over this packet. */ bp += hdrp->sbh_totlen; } #else /* SUNOS5 */ /* * It's just a packet, no buffering. */ if (strdata.len) { /* * Since we're not on SunOS5, that means we * don't have DLIOCRAW, so we don't have the * packet frame header. So, we need to * bypass that level of filtering. */ pkt_dispatch(bp, strdata.len, 0, htons(DLPI_DEFAULTSAP), 0); } #endif /* SUNOS5 */ } #endif /* USE_DLPI */ #ifdef USE_NIT /* * Flush the read queue of any packets that accumulated * during setup time. */ for (i=0; i < ninterfaces; i++) { flush_nit(if_fd[i]); tdrops[i] = 0; } for (;;) { FD_ZERO(&readfds); for (i=0; i < ninterfaces; i++) FD_SET(if_fd[i], &readfds); /* * See which nets have packets to read. */ cc = select(NFDBITS, &readfds, (fd_set *) 0, (fd_set *) 0, 0); if ((cc < 0) && (errno != EINTR)) { error("select"); finish(-1); } if (cc == 0) { continue; } /* * For each interface... */ for (i=0; i < ninterfaces; i++) { /* * Nothing to read. */ if (!FD_ISSET(if_fd[i], &readfds)) continue; /* * Now read packets from the nit device. */ if ((cc = read(if_fd[i], buf, NIT_CHUNKSIZE)) <= 0) continue; bufstop = buf + cc; bp = buf; /* * Loop through the chunk, extracting packets. */ while (bp < bufstop) { cp = bp; /* * Get the nit header. */ hdrp = (struct nit_bufhdr *) cp; cp += sizeof(struct nit_bufhdr); /* * Get the time stamp. */ tstamp = (struct nit_iftime *) cp; cp += sizeof(struct nit_iftime); /* * Get the number of dropped packets. */ ndp = (struct nit_ifdrops *) cp; cp += sizeof(struct nit_ifdrops); int_pkt_drops += ndp->nh_drops - tdrops[i]; pkt_drops += ndp->nh_drops - tdrops[i]; tdrops[i] = ndp->nh_drops; /* * Filter the packet. */ #ifdef notdef /* * This is how it *should* be. But the NIT * device rips off the FDDI packet header * and the 802.2 LLC header, and replaces * them with an ethernet packet header. */ if (if_dlt[i] == DLT_FDDI) { pkt_filter_fddi(cp, hdrp->nhb_msglen, &tstamp->nh_timestamp); } else { pkt_filter_ether(cp, hdrp->nhb_msglen, &tstamp->nh_timestamp); } #else /* * So... we just do this instead for both * ethernet and FDDI. Strange but true. */ pkt_filter_ether(cp, hdrp->nhb_msglen, &tstamp->nh_timestamp); #endif /* * Skip over this packet. */ bp += hdrp->nhb_totlen; } } #endif /* USE_NIT */ #ifdef USE_PFILT /* * Flush the read queue of any packets that accumulated * during setup time. */ for (i=0; i < ninterfaces; i++) flush_pfilt(if_fd[i]); for (;;) { FD_ZERO(&readfds); for (i=0; i < ninterfaces; i++) FD_SET(if_fd[i], &readfds); /* * See which interfaces have any packets to read. */ cc = select(NFDBITS, &readfds, (fd_set *) 0, (fd_set *) 0, 0); if ((cc < 0) && (errno != EINTR)) { error("select"); finish(-1); } if (cc == 0) { continue; } /* * Now read packets from the packet filter device. */ for (i=0; i < ninterfaces; i++) { if (!FD_ISSET(if_fd[i], &readfds)) continue; if ((cc = read(if_fd[i], buf, PFILT_CHUNKSIZE)) < 0) { lseek(if_fd[i], 0L, 0); /* * Might have read MAXINT bytes. Try again. */ if ((cc = read(if_fd[i], buf, PFILT_CHUNKSIZE)) < 0) { error("pfilt read"); finish(-1); } } bp = buf; /* * Loop through buffer, extracting packets. */ while (cc > 0) { /* * Avoid alignment issues. */ (void) bcopy(bp, &stamp, sizeof(stamp)); /* * Treat entire buffer as garbage. */ if (stamp.ens_stamplen != sizeof(stamp)) break; /* * Get the number of dropped packets. */ int_pkt_drops += stamp.ens_dropped; pkt_drops += stamp.ens_dropped; /* * Filter the packet. */ datalen = stamp.ens_count; if (datalen > truncation) datalen = truncation; if (if_dlt[i] == DLT_FDDI) { /* Weird Ultrix padding */ pkt_filter_fddi(&(bp[sizeof(stamp) + 3]), datalen, &stamp.ens_tstamp); } else pkt_filter_ether(&(bp[sizeof(stamp)]), datalen, &stamp.ens_tstamp); /* * Skip over this packet. */ if (cc == (datalen + sizeof(stamp))) break; datalen = ENALIGN(datalen); datalen += sizeof(stamp); cc -= datalen; bp += datalen; } } #endif /* USE_PFILT */ #ifdef USE_SNOOP /* * Flush the read queue of any packets that accumulated * during setup time. */ for (i=0; i < ninterfaces; i++) { flush_snoop(if_fd[i]); tdrops[i] = 0; } /* * Now read packets from the snooper. */ for (;;) { int dropped; FD_ZERO(&readfds); for (i=0; i < ninterfaces; i++) FD_SET(if_fd[i], &readfds); /* * See which nets have packets to read. */ cc = select(NFDBITS, &readfds, (fd_set *) 0, (fd_set *) 0, 0); if ((cc < 0) && (errno != EINTR)) { error("select"); finish(-1); } if (cc == 0) { continue; } /* * For each interface... */ for (i=0; i < ninterfaces; i++) { /* * Nothing to read. */ if (!FD_ISSET(if_fd[i], &readfds)) continue; /* * Now read packets from the nit device. */ if ((cc = read(if_fd[i], &ep, sizeof(ep))) <= 0) continue; if (do_update) { /* * Get the number of dropped packets. */ if (ioctl(if_fd[i], SIOCRAWSTATS, &rs) == 0) { dropped = rs.rs_snoop.ss_ifdrops + rs.rs_snoop.ss_sbdrops; int_pkt_drops += dropped - tdrops[i]; pkt_drops += dropped - tdrops[i]; tdrops[i] = dropped; } } /* * Filter the packet. */ if (if_dlt[i] == DLT_FDDI) { /* * This probably won't work. */ pkt_filter_fddi(&ep.ether, ep.snoop.snoop_packetlen, &ep.snoop.snoop_timestamp); } else { pkt_filter_ether(&ep.ether, ep.snoop.snoop_packetlen, &ep.snoop.snoop_timestamp); } } #endif /* USE_SNOOP */ tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&readfds); FD_SET(0, &readfds); /* * See if a command has been typed. */ if (!bgflag) { cc = select(NFDBITS, &readfds, (fd_set *) 0, (fd_set *) 0, &tv); if ((cc > 0) && FD_ISSET(0, &readfds)) command(); } } }