xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop.c (revision 1ce6354a8346a429d5b2e0874eb276acfd7e7b23)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54ab75253Smrj  * Common Development and Distribution License (the "License").
64ab75253Smrj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
214ab75253Smrj 
227c478bd9Sstevel@tonic-gate /*
23b78ff649Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <unistd.h>
297c478bd9Sstevel@tonic-gate #include <stropts.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <setjmp.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/time.h>
397c478bd9Sstevel@tonic-gate #include <signal.h>
407c478bd9Sstevel@tonic-gate #include <sys/mman.h>
417c478bd9Sstevel@tonic-gate #include <assert.h>
427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/socket.h>
457c478bd9Sstevel@tonic-gate #include <sys/pfmod.h>
467c478bd9Sstevel@tonic-gate #include <net/if.h>
477c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h>
487c478bd9Sstevel@tonic-gate #include <netinet/in.h>
497c478bd9Sstevel@tonic-gate #include <netinet/if_ether.h>
507c478bd9Sstevel@tonic-gate #include <netdb.h>
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include "snoop.h"
537c478bd9Sstevel@tonic-gate 
5445916cd2Sjpk static int snaplen;
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* Global error recovery variables */
577c478bd9Sstevel@tonic-gate sigjmp_buf jmp_env, ojmp_env;		/* error recovery jmp buf */
587c478bd9Sstevel@tonic-gate int snoop_nrecover;			/* number of recoveries on curr pkt */
597c478bd9Sstevel@tonic-gate int quitting;				/* user termination flag */
607c478bd9Sstevel@tonic-gate 
6145916cd2Sjpk static struct snoop_handler *snoop_hp;		/* global alarm handler head */
6245916cd2Sjpk static struct snoop_handler *snoop_tp;		/* global alarm handler tail */
6345916cd2Sjpk static time_t snoop_nalarm;			/* time of next alarm */
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* protected interpreter output areas */
667c478bd9Sstevel@tonic-gate #define	MAXSUM		8
677c478bd9Sstevel@tonic-gate #define	REDZONE		64
687c478bd9Sstevel@tonic-gate static char *sumline[MAXSUM];
697c478bd9Sstevel@tonic-gate static char *detail_line;
707c478bd9Sstevel@tonic-gate static char *line;
717c478bd9Sstevel@tonic-gate static char *encap;
727c478bd9Sstevel@tonic-gate 
7345916cd2Sjpk static int audio;
747c478bd9Sstevel@tonic-gate int maxcount;	/* maximum no of packets to capture */
757c478bd9Sstevel@tonic-gate int count;	/* count of packets captured */
7645916cd2Sjpk static int sumcount;
777c478bd9Sstevel@tonic-gate int x_offset = -1;
787c478bd9Sstevel@tonic-gate int x_length = 0x7fffffff;
797c478bd9Sstevel@tonic-gate FILE *namefile;
80b127ac41SPhilip Kirk boolean_t Pflg;
81b127ac41SPhilip Kirk boolean_t Iflg;
82b127ac41SPhilip Kirk boolean_t qflg;
83b127ac41SPhilip Kirk boolean_t rflg;
847c478bd9Sstevel@tonic-gate #ifdef	DEBUG
85b127ac41SPhilip Kirk boolean_t zflg;
867c478bd9Sstevel@tonic-gate #endif
877c478bd9Sstevel@tonic-gate struct Pf_ext_packetfilt pf;
887c478bd9Sstevel@tonic-gate 
89605445d5Sdg199075 static int vlanid = 0;
90605445d5Sdg199075 
9145916cd2Sjpk static void usage(void);
9245916cd2Sjpk static void snoop_sigrecover(int sig, siginfo_t *info, void *p);
937c478bd9Sstevel@tonic-gate static char *protmalloc(size_t);
947c478bd9Sstevel@tonic-gate static void resetperm(void);
957c478bd9Sstevel@tonic-gate 
962e3b6467Skcpoon int
main(int argc,char ** argv)972e3b6467Skcpoon main(int argc, char **argv)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate 	int c;
1007c478bd9Sstevel@tonic-gate 	int filter = 0;
1017c478bd9Sstevel@tonic-gate 	int flags = F_SUM;
1027c478bd9Sstevel@tonic-gate 	struct Pf_ext_packetfilt *fp = NULL;
1037c478bd9Sstevel@tonic-gate 	char *icapfile = NULL;
1047c478bd9Sstevel@tonic-gate 	char *ocapfile = NULL;
105b127ac41SPhilip Kirk 	boolean_t nflg = B_FALSE;
106b127ac41SPhilip Kirk 	boolean_t Nflg = B_FALSE;
1077c478bd9Sstevel@tonic-gate 	int Cflg = 0;
108b127ac41SPhilip Kirk 	boolean_t Uflg = B_FALSE;
1097c478bd9Sstevel@tonic-gate 	int first = 1;
1107c478bd9Sstevel@tonic-gate 	int last  = 0x7fffffff;
111b127ac41SPhilip Kirk 	boolean_t use_kern_pf;
1127c478bd9Sstevel@tonic-gate 	char *p, *p2;
1137c478bd9Sstevel@tonic-gate 	char names[MAXPATHLEN + 1];
1147c478bd9Sstevel@tonic-gate 	char self[MAXHOSTNAMELEN + 1];
1157c478bd9Sstevel@tonic-gate 	char *argstr = NULL;
1167c478bd9Sstevel@tonic-gate 	void (*proc)();
1177c478bd9Sstevel@tonic-gate 	char *audiodev;
1187c478bd9Sstevel@tonic-gate 	int ret;
1197c478bd9Sstevel@tonic-gate 	struct sigaction sigact;
1207c478bd9Sstevel@tonic-gate 	stack_t sigstk;
1217c478bd9Sstevel@tonic-gate 	char *output_area;
1227c478bd9Sstevel@tonic-gate 	int nbytes;
123b78ff649Smeem 	char *datalink = NULL;
124c7e4935fSss150715 	dlpi_handle_t dh;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	names[0] = '\0';
1277c478bd9Sstevel@tonic-gate 	/*
1287c478bd9Sstevel@tonic-gate 	 * Global error recovery: Prepare for interpreter failures
1297c478bd9Sstevel@tonic-gate 	 * with corrupted packets or confused interpreters.
1307c478bd9Sstevel@tonic-gate 	 * Allocate protected output and stack areas, with generous
1317c478bd9Sstevel@tonic-gate 	 * red-zones.
1327c478bd9Sstevel@tonic-gate 	 */
1337c478bd9Sstevel@tonic-gate 	nbytes = (MAXSUM + 3) * (MAXLINE + REDZONE);
1347c478bd9Sstevel@tonic-gate 	output_area = protmalloc(nbytes);
1357c478bd9Sstevel@tonic-gate 	if (output_area == NULL) {
1367c478bd9Sstevel@tonic-gate 		perror("Warning: mmap");
1377c478bd9Sstevel@tonic-gate 		exit(1);
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	/* Allocate protected output areas */
1417c478bd9Sstevel@tonic-gate 	for (ret = 0; ret < MAXSUM; ret++) {
1427c478bd9Sstevel@tonic-gate 		sumline[ret] = (char *)output_area;
1437c478bd9Sstevel@tonic-gate 		output_area += (MAXLINE + REDZONE);
1447c478bd9Sstevel@tonic-gate 	}
1457c478bd9Sstevel@tonic-gate 	detail_line = output_area;
1467c478bd9Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1477c478bd9Sstevel@tonic-gate 	line = output_area;
1487c478bd9Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1497c478bd9Sstevel@tonic-gate 	encap = output_area;
1507c478bd9Sstevel@tonic-gate 	output_area += MAXLINE + REDZONE;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* Initialize an alternate signal stack to increase robustness */
1537c478bd9Sstevel@tonic-gate 	if ((sigstk.ss_sp = (char *)malloc(SIGSTKSZ+REDZONE)) == NULL) {
1547c478bd9Sstevel@tonic-gate 		perror("Warning: malloc");
1557c478bd9Sstevel@tonic-gate 		exit(1);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 	sigstk.ss_size = SIGSTKSZ;
1587c478bd9Sstevel@tonic-gate 	sigstk.ss_flags = 0;
1597c478bd9Sstevel@tonic-gate 	if (sigaltstack(&sigstk, (stack_t *)NULL) < 0) {
1607c478bd9Sstevel@tonic-gate 		perror("Warning: sigaltstack");
1617c478bd9Sstevel@tonic-gate 		exit(1);
1627c478bd9Sstevel@tonic-gate 	}
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	/* Initialize a master signal handler */
1657c478bd9Sstevel@tonic-gate 	sigact.sa_handler = NULL;
1667c478bd9Sstevel@tonic-gate 	sigact.sa_sigaction = snoop_sigrecover;
16745916cd2Sjpk 	(void) sigemptyset(&sigact.sa_mask);
1687c478bd9Sstevel@tonic-gate 	sigact.sa_flags = SA_ONSTACK|SA_SIGINFO;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	/* Register master signal handler */
1717c478bd9Sstevel@tonic-gate 	if (sigaction(SIGHUP, &sigact, (struct sigaction *)NULL) < 0) {
1727c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1737c478bd9Sstevel@tonic-gate 		exit(1);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
1767c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1777c478bd9Sstevel@tonic-gate 		exit(1);
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 	if (sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL) < 0) {
1807c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1817c478bd9Sstevel@tonic-gate 		exit(1);
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 	if (sigaction(SIGILL, &sigact, (struct sigaction *)NULL) < 0) {
1847c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1857c478bd9Sstevel@tonic-gate 		exit(1);
1867c478bd9Sstevel@tonic-gate 	}
1877c478bd9Sstevel@tonic-gate 	if (sigaction(SIGTRAP, &sigact, (struct sigaction *)NULL) < 0) {
1887c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1897c478bd9Sstevel@tonic-gate 		exit(1);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 	if (sigaction(SIGIOT, &sigact, (struct sigaction *)NULL) < 0) {
1927c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1937c478bd9Sstevel@tonic-gate 		exit(1);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	if (sigaction(SIGEMT, &sigact, (struct sigaction *)NULL) < 0) {
1967c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
1977c478bd9Sstevel@tonic-gate 		exit(1);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	if (sigaction(SIGFPE, &sigact, (struct sigaction *)NULL) < 0) {
2007c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2017c478bd9Sstevel@tonic-gate 		exit(1);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 	if (sigaction(SIGBUS, &sigact, (struct sigaction *)NULL) < 0) {
2047c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2057c478bd9Sstevel@tonic-gate 		exit(1);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 	if (sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL) < 0) {
2087c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2097c478bd9Sstevel@tonic-gate 		exit(1);
2107c478bd9Sstevel@tonic-gate 	}
2117c478bd9Sstevel@tonic-gate 	if (sigaction(SIGSYS, &sigact, (struct sigaction *)NULL) < 0) {
2127c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2137c478bd9Sstevel@tonic-gate 		exit(1);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 	if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) < 0) {
2167c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2177c478bd9Sstevel@tonic-gate 		exit(1);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 	if (sigaction(SIGTERM, &sigact, (struct sigaction *)NULL) < 0) {
2207c478bd9Sstevel@tonic-gate 		perror("Warning: sigaction");
2217c478bd9Sstevel@tonic-gate 		exit(1);
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	/* Prepare for failure during program initialization/exit */
2257c478bd9Sstevel@tonic-gate 	if (sigsetjmp(jmp_env, 1)) {
2267c478bd9Sstevel@tonic-gate 		exit(1);
2277c478bd9Sstevel@tonic-gate 	}
22845916cd2Sjpk 	(void) setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
2297c478bd9Sstevel@tonic-gate 
230b127ac41SPhilip Kirk 	while ((c = getopt(argc, argv, "at:CPDSi:o:Nn:s:d:I:vVp:f:c:x:U?rqz"))
2317c478bd9Sstevel@tonic-gate 	    != EOF) {
2327c478bd9Sstevel@tonic-gate 		switch (c) {
2337c478bd9Sstevel@tonic-gate 		case 'a':
2347c478bd9Sstevel@tonic-gate 			audiodev = getenv("AUDIODEV");
2357c478bd9Sstevel@tonic-gate 			if (audiodev == NULL)
2367c478bd9Sstevel@tonic-gate 				audiodev = "/dev/audio";
2377c478bd9Sstevel@tonic-gate 			audio = open(audiodev, O_WRONLY);
2387c478bd9Sstevel@tonic-gate 			if (audio < 0) {
2397c478bd9Sstevel@tonic-gate 				pr_err("Audio device %s: %m",
2407c478bd9Sstevel@tonic-gate 				    audiodev);
2417c478bd9Sstevel@tonic-gate 				exit(1);
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 			break;
2447c478bd9Sstevel@tonic-gate 		case 't':
2457c478bd9Sstevel@tonic-gate 			flags |= F_TIME;
2467c478bd9Sstevel@tonic-gate 			switch (*optarg) {
2477c478bd9Sstevel@tonic-gate 			case 'r':	flags |= F_RTIME; break;
2487c478bd9Sstevel@tonic-gate 			case 'a':	flags |= F_ATIME; break;
2497c478bd9Sstevel@tonic-gate 			case 'd':	break;
2507c478bd9Sstevel@tonic-gate 			default:	usage();
2517c478bd9Sstevel@tonic-gate 			}
2527c478bd9Sstevel@tonic-gate 			break;
253b127ac41SPhilip Kirk 		case 'I':
254b78ff649Smeem 			if (datalink != NULL)
255b127ac41SPhilip Kirk 				usage();
256b127ac41SPhilip Kirk 			Iflg = B_TRUE;
257b78ff649Smeem 			datalink = optarg;
258b127ac41SPhilip Kirk 			break;
2597c478bd9Sstevel@tonic-gate 		case 'P':
260b127ac41SPhilip Kirk 			Pflg = B_TRUE;
2617c478bd9Sstevel@tonic-gate 			break;
2627c478bd9Sstevel@tonic-gate 		case 'D':
2637c478bd9Sstevel@tonic-gate 			flags |= F_DROPS;
2647c478bd9Sstevel@tonic-gate 			break;
2657c478bd9Sstevel@tonic-gate 		case 'S':
2667c478bd9Sstevel@tonic-gate 			flags |= F_LEN;
2677c478bd9Sstevel@tonic-gate 			break;
2687c478bd9Sstevel@tonic-gate 		case 'i':
2697c478bd9Sstevel@tonic-gate 			icapfile = optarg;
2707c478bd9Sstevel@tonic-gate 			break;
2717c478bd9Sstevel@tonic-gate 		case 'o':
2727c478bd9Sstevel@tonic-gate 			ocapfile = optarg;
2737c478bd9Sstevel@tonic-gate 			break;
2747c478bd9Sstevel@tonic-gate 		case 'N':
275b127ac41SPhilip Kirk 			Nflg = B_TRUE;
2767c478bd9Sstevel@tonic-gate 			break;
2777c478bd9Sstevel@tonic-gate 		case 'n':
278b127ac41SPhilip Kirk 			nflg = B_TRUE;
2797c478bd9Sstevel@tonic-gate 			(void) strlcpy(names, optarg, MAXPATHLEN);
2807c478bd9Sstevel@tonic-gate 			break;
2817c478bd9Sstevel@tonic-gate 		case 's':
2827c478bd9Sstevel@tonic-gate 			snaplen = atoi(optarg);
2837c478bd9Sstevel@tonic-gate 			break;
2847c478bd9Sstevel@tonic-gate 		case 'd':
285b127ac41SPhilip Kirk 			if (Iflg)
286b127ac41SPhilip Kirk 				usage();
287b78ff649Smeem 			datalink = optarg;
2887c478bd9Sstevel@tonic-gate 			break;
2897c478bd9Sstevel@tonic-gate 		case 'v':
2907c478bd9Sstevel@tonic-gate 			flags &= ~(F_SUM);
2917c478bd9Sstevel@tonic-gate 			flags |= F_DTAIL;
2927c478bd9Sstevel@tonic-gate 			break;
2937c478bd9Sstevel@tonic-gate 		case 'V':
2947c478bd9Sstevel@tonic-gate 			flags |= F_ALLSUM;
2957c478bd9Sstevel@tonic-gate 			break;
2967c478bd9Sstevel@tonic-gate 		case 'p':
2977c478bd9Sstevel@tonic-gate 			p = optarg;
2987c478bd9Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
2997c478bd9Sstevel@tonic-gate 			if (p2 == NULL) {
3007c478bd9Sstevel@tonic-gate 				first = last = atoi(p);
3017c478bd9Sstevel@tonic-gate 			} else {
3027c478bd9Sstevel@tonic-gate 				*p2++ = '\0';
3037c478bd9Sstevel@tonic-gate 				first = atoi(p);
3047c478bd9Sstevel@tonic-gate 				last = atoi(p2);
3057c478bd9Sstevel@tonic-gate 			}
3067c478bd9Sstevel@tonic-gate 			break;
3077c478bd9Sstevel@tonic-gate 		case 'f':
3087c478bd9Sstevel@tonic-gate 			(void) gethostname(self, MAXHOSTNAMELEN);
3097c478bd9Sstevel@tonic-gate 			p = strchr(optarg, ':');
3107c478bd9Sstevel@tonic-gate 			if (p) {
3117c478bd9Sstevel@tonic-gate 				*p = '\0';
3127c478bd9Sstevel@tonic-gate 				if (strcmp(optarg, self) == 0 ||
3137c478bd9Sstevel@tonic-gate 				    strcmp(p+1, self) == 0)
3147c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3157c478bd9Sstevel@tonic-gate 				"Warning: cannot capture packets from %s\n",
3167c478bd9Sstevel@tonic-gate 				    self);
3177c478bd9Sstevel@tonic-gate 				*p = ' ';
3187c478bd9Sstevel@tonic-gate 			} else if (strcmp(optarg, self) == 0)
3197c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
3207c478bd9Sstevel@tonic-gate 				"Warning: cannot capture packets from %s\n",
3217c478bd9Sstevel@tonic-gate 				    self);
3227c478bd9Sstevel@tonic-gate 			argstr = optarg;
3237c478bd9Sstevel@tonic-gate 			break;
3247c478bd9Sstevel@tonic-gate 		case 'x':
3257c478bd9Sstevel@tonic-gate 			p = optarg;
3267c478bd9Sstevel@tonic-gate 			p2 = strpbrk(p, ",:-");
3277c478bd9Sstevel@tonic-gate 			if (p2 == NULL) {
3287c478bd9Sstevel@tonic-gate 				x_offset = atoi(p);
3297c478bd9Sstevel@tonic-gate 				x_length = -1;
3307c478bd9Sstevel@tonic-gate 			} else {
3317c478bd9Sstevel@tonic-gate 				*p2++ = '\0';
3327c478bd9Sstevel@tonic-gate 				x_offset = atoi(p);
3337c478bd9Sstevel@tonic-gate 				x_length = atoi(p2);
3347c478bd9Sstevel@tonic-gate 			}
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 		case 'c':
3377c478bd9Sstevel@tonic-gate 			maxcount = atoi(optarg);
3387c478bd9Sstevel@tonic-gate 			break;
3397c478bd9Sstevel@tonic-gate 		case 'C':
340b127ac41SPhilip Kirk 			Cflg = B_TRUE;
3417c478bd9Sstevel@tonic-gate 			break;
3427c478bd9Sstevel@tonic-gate 		case 'q':
3437c478bd9Sstevel@tonic-gate 			qflg = B_TRUE;
3447c478bd9Sstevel@tonic-gate 			break;
3457c478bd9Sstevel@tonic-gate 		case 'r':
3467c478bd9Sstevel@tonic-gate 			rflg = B_TRUE;
3477c478bd9Sstevel@tonic-gate 			break;
348b127ac41SPhilip Kirk 		case 'U':
349b127ac41SPhilip Kirk 			Uflg = B_TRUE;
350b127ac41SPhilip Kirk 			break;
3517c478bd9Sstevel@tonic-gate #ifdef	DEBUG
3527c478bd9Sstevel@tonic-gate 		case 'z':
3537c478bd9Sstevel@tonic-gate 			zflg = B_TRUE;
3547c478bd9Sstevel@tonic-gate 			break;
3557c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
3567c478bd9Sstevel@tonic-gate 		case '?':
3577c478bd9Sstevel@tonic-gate 		default:
3587c478bd9Sstevel@tonic-gate 			usage();
3597c478bd9Sstevel@tonic-gate 		}
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (argc > optind)
3637c478bd9Sstevel@tonic-gate 		argstr = (char *)concat_args(&argv[optind], argc - optind);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/*
3667c478bd9Sstevel@tonic-gate 	 * Need to know before we decide on filtering method some things
3677c478bd9Sstevel@tonic-gate 	 * about the interface.  So, go ahead and do part of the initialization
368b78ff649Smeem 	 * now so we have that data.  Note that if no datalink is specified,
369b78ff649Smeem 	 * open_datalink() selects one and returns it.  In an ideal world,
3707c478bd9Sstevel@tonic-gate 	 * it might be nice if the "correct" interface for the filter
3717c478bd9Sstevel@tonic-gate 	 * requested was chosen, but that's too hard.
3727c478bd9Sstevel@tonic-gate 	 */
3737c478bd9Sstevel@tonic-gate 	if (!icapfile) {
374b78ff649Smeem 		use_kern_pf = open_datalink(&dh, datalink);
3757c478bd9Sstevel@tonic-gate 	} else {
376b127ac41SPhilip Kirk 		use_kern_pf = B_FALSE;
3777c478bd9Sstevel@tonic-gate 		cap_open_read(icapfile);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		if (!nflg) {
3807c478bd9Sstevel@tonic-gate 			names[0] = '\0';
3817c478bd9Sstevel@tonic-gate 			(void) strlcpy(names, icapfile, MAXPATHLEN);
3827c478bd9Sstevel@tonic-gate 			(void) strlcat(names, ".names", MAXPATHLEN);
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 
386b127ac41SPhilip Kirk 	if (Uflg)
387b127ac41SPhilip Kirk 		use_kern_pf = B_FALSE;
388b127ac41SPhilip Kirk 
3897c478bd9Sstevel@tonic-gate 	/* attempt to read .names file if it exists before filtering */
3907c478bd9Sstevel@tonic-gate 	if ((!Nflg) && names[0] != '\0') {
3917c478bd9Sstevel@tonic-gate 		if (access(names, F_OK) == 0) {
3927c478bd9Sstevel@tonic-gate 			load_names(names);
3937c478bd9Sstevel@tonic-gate 		} else if (nflg) {
3947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s not found\n", names);
3957c478bd9Sstevel@tonic-gate 			exit(1);
3967c478bd9Sstevel@tonic-gate 		}
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (argstr) {
400b127ac41SPhilip Kirk 		if (use_kern_pf) {
4017c478bd9Sstevel@tonic-gate 			ret = pf_compile(argstr, Cflg);
4027c478bd9Sstevel@tonic-gate 			switch (ret) {
4037c478bd9Sstevel@tonic-gate 			case 0:
4047c478bd9Sstevel@tonic-gate 				filter++;
4057c478bd9Sstevel@tonic-gate 				compile(argstr, Cflg);
4067c478bd9Sstevel@tonic-gate 				break;
4077c478bd9Sstevel@tonic-gate 			case 1:
4087c478bd9Sstevel@tonic-gate 				fp = &pf;
4097c478bd9Sstevel@tonic-gate 				break;
4107c478bd9Sstevel@tonic-gate 			case 2:
4117c478bd9Sstevel@tonic-gate 				fp = &pf;
4127c478bd9Sstevel@tonic-gate 				filter++;
4137c478bd9Sstevel@tonic-gate 				break;
4147c478bd9Sstevel@tonic-gate 			}
4157c478bd9Sstevel@tonic-gate 		} else {
4167c478bd9Sstevel@tonic-gate 			filter++;
4177c478bd9Sstevel@tonic-gate 			compile(argstr, Cflg);
4187c478bd9Sstevel@tonic-gate 		}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 		if (Cflg)
4217c478bd9Sstevel@tonic-gate 			exit(0);
4227c478bd9Sstevel@tonic-gate 	}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (flags & F_SUM)
4257c478bd9Sstevel@tonic-gate 		flags |= F_WHO;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	/*
4287c478bd9Sstevel@tonic-gate 	 * If the -o flag is set then capture packets
4297c478bd9Sstevel@tonic-gate 	 * directly to a file.  Don't attempt to
4307c478bd9Sstevel@tonic-gate 	 * interpret them on the fly (F_NOW).
4317c478bd9Sstevel@tonic-gate 	 * Note: capture to file is much less likely
4327c478bd9Sstevel@tonic-gate 	 * to drop packets since we don't spend cpu
4337c478bd9Sstevel@tonic-gate 	 * cycles running through the interpreters
4347c478bd9Sstevel@tonic-gate 	 * and possibly hanging in address-to-name
4357c478bd9Sstevel@tonic-gate 	 * mappings through the name service.
4367c478bd9Sstevel@tonic-gate 	 */
4377c478bd9Sstevel@tonic-gate 	if (ocapfile) {
4387c478bd9Sstevel@tonic-gate 		cap_open_write(ocapfile);
4397c478bd9Sstevel@tonic-gate 		proc = cap_write;
4407c478bd9Sstevel@tonic-gate 	} else {
4417c478bd9Sstevel@tonic-gate 		flags |= F_NOW;
4427c478bd9Sstevel@tonic-gate 		proc = process_pkt;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/*
4477c478bd9Sstevel@tonic-gate 	 * If the -i flag is set then get packets from
4487c478bd9Sstevel@tonic-gate 	 * the log file which has been previously captured
4497c478bd9Sstevel@tonic-gate 	 * with the -o option.
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	if (icapfile) {
4527c478bd9Sstevel@tonic-gate 		names[0] = '\0';
4537c478bd9Sstevel@tonic-gate 		(void) strlcpy(names, icapfile, MAXPATHLEN);
4547c478bd9Sstevel@tonic-gate 		(void) strlcat(names, ".names", MAXPATHLEN);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 		if (Nflg) {
4577c478bd9Sstevel@tonic-gate 			namefile = fopen(names, "w");
4587c478bd9Sstevel@tonic-gate 			if (namefile == NULL) {
4597c478bd9Sstevel@tonic-gate 				perror(names);
4607c478bd9Sstevel@tonic-gate 				exit(1);
4617c478bd9Sstevel@tonic-gate 			}
4627c478bd9Sstevel@tonic-gate 			flags = 0;
4637c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
4647c478bd9Sstevel@tonic-gate 			    "Creating name file %s\n", names);
4657c478bd9Sstevel@tonic-gate 		}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 		if (flags & F_DTAIL)
4687c478bd9Sstevel@tonic-gate 			flags = F_DTAIL;
4697c478bd9Sstevel@tonic-gate 		else
4707c478bd9Sstevel@tonic-gate 			flags |= F_NUM | F_TIME;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		resetperm();
4737c478bd9Sstevel@tonic-gate 		cap_read(first, last, filter, proc, flags);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 		if (Nflg)
4767c478bd9Sstevel@tonic-gate 			(void) fclose(namefile);
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	} else {
4797c478bd9Sstevel@tonic-gate 		const int chunksize = 8 * 8192;
4807c478bd9Sstevel@tonic-gate 		struct timeval timeout;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 		/*
4837c478bd9Sstevel@tonic-gate 		 * If listening to packets on audio
4847c478bd9Sstevel@tonic-gate 		 * then set the buffer timeout down
4857c478bd9Sstevel@tonic-gate 		 * to 1/10 sec.  A higher value
4867c478bd9Sstevel@tonic-gate 		 * makes the audio "bursty".
4877c478bd9Sstevel@tonic-gate 		 */
4887c478bd9Sstevel@tonic-gate 		if (audio) {
4897c478bd9Sstevel@tonic-gate 			timeout.tv_sec = 0;
4907c478bd9Sstevel@tonic-gate 			timeout.tv_usec = 100000;
4917c478bd9Sstevel@tonic-gate 		} else {
4927c478bd9Sstevel@tonic-gate 			timeout.tv_sec = 1;
4937c478bd9Sstevel@tonic-gate 			timeout.tv_usec = 0;
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 
496b78ff649Smeem 		init_datalink(dh, snaplen, chunksize, &timeout, fp);
4977c478bd9Sstevel@tonic-gate 		if (! qflg && ocapfile)
4987c478bd9Sstevel@tonic-gate 			show_count();
4997c478bd9Sstevel@tonic-gate 		resetperm();
500c7e4935fSss150715 		net_read(dh, chunksize, filter, proc, flags);
501c7e4935fSss150715 		dlpi_close(dh);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 		if (!(flags & F_NOW))
50445916cd2Sjpk 			(void) printf("\n");
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (ocapfile)
5087c478bd9Sstevel@tonic-gate 		cap_close();
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (0);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
51345916cd2Sjpk static int tone[] = {
514ba1637f8Smh138676 0x076113, 0x153333, 0x147317, 0x144311, 0x147315, 0x050353, 0x037103, 0x051106,
515ba1637f8Smh138676 0x157155, 0x142723, 0x133273, 0x134664, 0x051712, 0x024465, 0x026447, 0x072473,
516ba1637f8Smh138676 0x136715, 0x126257, 0x135256, 0x047344, 0x034476, 0x027464, 0x036062, 0x133334,
517ba1637f8Smh138676 0x127256, 0x130660, 0x136262, 0x040724, 0x016446, 0x025437, 0x137171, 0x127672,
518ba1637f8Smh138676 0x124655, 0x134654, 0x032741, 0x021447, 0x037450, 0x125675, 0x127650, 0x077277,
519ba1637f8Smh138676 0x046514, 0x036077, 0x035471, 0x147131, 0x136272, 0x162720, 0x166151, 0x037527,
5207c478bd9Sstevel@tonic-gate };
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate /*
523ba1637f8Smh138676  * Make a sound on /dev/audio according to the length of the packet.  The
524ba1637f8Smh138676  * tone data was ripped from /usr/share/audio/samples/au/bark.au.  The
525ba1637f8Smh138676  * amount of waveform used is a function of packet length e.g.  a series
526ba1637f8Smh138676  * of small packets is heard as clicks, whereas a series of NFS packets in
527ba1637f8Smh138676  * an 8k read sounds like a "WHAAAARP".
5287c478bd9Sstevel@tonic-gate  */
5297c478bd9Sstevel@tonic-gate void
click(int len)530*1ce6354aSYuri Pankov click(int len)
5317c478bd9Sstevel@tonic-gate {
5327c478bd9Sstevel@tonic-gate 	len /= 8;
5337c478bd9Sstevel@tonic-gate 	len = len ? len : 4;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	if (audio) {
53645916cd2Sjpk 		(void) write(audio, tone, len);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate /* Display a count of packets */
5417c478bd9Sstevel@tonic-gate void
show_count()5427c478bd9Sstevel@tonic-gate show_count()
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	static int prev = -1;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (count == prev)
5477c478bd9Sstevel@tonic-gate 		return;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	prev = count;
5507c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\r%d ", count);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate #define	ENCAP_LEN	16	/* Hold "(NN encap)" */
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate /*
5567c478bd9Sstevel@tonic-gate  * Display data that's external to the packet.
5577c478bd9Sstevel@tonic-gate  * This constitutes the first half of the summary
5587c478bd9Sstevel@tonic-gate  * line display.
5597c478bd9Sstevel@tonic-gate  */
5607c478bd9Sstevel@tonic-gate void
show_pktinfo(int flags,int num,char * src,char * dst,struct timeval * ptvp,struct timeval * tvp,int drops,int len)561*1ce6354aSYuri Pankov show_pktinfo(int flags, int num, char *src, char *dst, struct timeval *ptvp,
562*1ce6354aSYuri Pankov     struct timeval *tvp, int drops, int len)
5637c478bd9Sstevel@tonic-gate {
5647c478bd9Sstevel@tonic-gate 	struct tm *tm;
5657c478bd9Sstevel@tonic-gate 	static struct timeval tvp0;
5667c478bd9Sstevel@tonic-gate 	int sec, usec;
5677c478bd9Sstevel@tonic-gate 	char *lp = line;
5687c478bd9Sstevel@tonic-gate 	int i, start;
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 	if (flags & F_NUM) {
57145916cd2Sjpk 		(void) sprintf(lp, "%3d ", num);
5727c478bd9Sstevel@tonic-gate 		lp += strlen(lp);
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 	tm = localtime(&tvp->tv_sec);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (flags & F_TIME) {
5777c478bd9Sstevel@tonic-gate 		if (flags & F_ATIME) {
578*1ce6354aSYuri Pankov 			(void) sprintf(lp, "%02d:%02d:%02d.%05d ",
5797c478bd9Sstevel@tonic-gate 			    tm->tm_hour, tm->tm_min, tm->tm_sec,
58045916cd2Sjpk 			    (int)tvp->tv_usec / 10);
5817c478bd9Sstevel@tonic-gate 			lp += strlen(lp);
5827c478bd9Sstevel@tonic-gate 		} else {
5837c478bd9Sstevel@tonic-gate 			if (flags & F_RTIME) {
5847c478bd9Sstevel@tonic-gate 				if (tvp0.tv_sec == 0) {
5857c478bd9Sstevel@tonic-gate 					tvp0.tv_sec = tvp->tv_sec;
5867c478bd9Sstevel@tonic-gate 					tvp0.tv_usec = tvp->tv_usec;
5877c478bd9Sstevel@tonic-gate 				}
5887c478bd9Sstevel@tonic-gate 				ptvp = &tvp0;
5897c478bd9Sstevel@tonic-gate 			}
5907c478bd9Sstevel@tonic-gate 			sec  = tvp->tv_sec  - ptvp->tv_sec;
5917c478bd9Sstevel@tonic-gate 			usec = tvp->tv_usec - ptvp->tv_usec;
5927c478bd9Sstevel@tonic-gate 			if (usec < 0) {
5937c478bd9Sstevel@tonic-gate 				usec += 1000000;
5947c478bd9Sstevel@tonic-gate 				sec  -= 1;
5957c478bd9Sstevel@tonic-gate 			}
59645916cd2Sjpk 			(void) sprintf(lp, "%3d.%05d ", sec, usec / 10);
5977c478bd9Sstevel@tonic-gate 			lp += strlen(lp);
5987c478bd9Sstevel@tonic-gate 		}
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
601605445d5Sdg199075 	if ((flags & F_SUM) && !(flags & F_ALLSUM) && (vlanid != 0)) {
602605445d5Sdg199075 		(void) snprintf(lp, MAXLINE, "VLAN#%i: ", vlanid);
603605445d5Sdg199075 		lp += strlen(lp);
604605445d5Sdg199075 	}
605605445d5Sdg199075 
6067c478bd9Sstevel@tonic-gate 	if (flags & F_WHO) {
60745916cd2Sjpk 		(void) sprintf(lp, "%12s -> %-12s ", src, dst);
6087c478bd9Sstevel@tonic-gate 		lp += strlen(lp);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	if (flags & F_DROPS) {
61245916cd2Sjpk 		(void) sprintf(lp, "drops: %d ", drops);
6137c478bd9Sstevel@tonic-gate 		lp += strlen(lp);
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	if (flags & F_LEN) {
61745916cd2Sjpk 		(void) sprintf(lp, "length: %4d  ", len);
6187c478bd9Sstevel@tonic-gate 		lp += strlen(lp);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	if (flags & F_SUM) {
6227c478bd9Sstevel@tonic-gate 		if (flags & F_ALLSUM)
62345916cd2Sjpk 			(void) printf("________________________________\n");
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		start = flags & F_ALLSUM ? 0 : sumcount - 1;
62645916cd2Sjpk 		(void) sprintf(encap, "  (%d encap)", total_encap_levels - 1);
62745916cd2Sjpk 		(void) printf("%s%s%s\n", line, sumline[start],
6287c478bd9Sstevel@tonic-gate 		    ((flags & F_ALLSUM) || (total_encap_levels == 1)) ? "" :
6297c478bd9Sstevel@tonic-gate 		    encap);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 		for (i = start + 1; i < sumcount; i++)
63245916cd2Sjpk 			(void) printf("%s%s\n", line, sumline[i]);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 		sumcount = 0;
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	if (flags & F_DTAIL) {
63845916cd2Sjpk 		(void) printf("%s\n\n", detail_line);
6397c478bd9Sstevel@tonic-gate 		detail_line[0] = '\0';
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate }
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate /*
644605445d5Sdg199075  * The following three routines are called back
6457c478bd9Sstevel@tonic-gate  * from the interpreters to display their stuff.
6467c478bd9Sstevel@tonic-gate  * The theory is that when snoop becomes a window
6477c478bd9Sstevel@tonic-gate  * based tool we can just supply a new version of
6487c478bd9Sstevel@tonic-gate  * get_sum_line and get_detail_line and not have
6497c478bd9Sstevel@tonic-gate  * to touch the interpreters at all.
6507c478bd9Sstevel@tonic-gate  */
6517c478bd9Sstevel@tonic-gate char *
get_sum_line()6527c478bd9Sstevel@tonic-gate get_sum_line()
6537c478bd9Sstevel@tonic-gate {
6547c478bd9Sstevel@tonic-gate 	int tsumcount = sumcount;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (sumcount >= MAXSUM) {
6577c478bd9Sstevel@tonic-gate 		sumcount = 0;			/* error recovery */
6587c478bd9Sstevel@tonic-gate 		pr_err(
6597c478bd9Sstevel@tonic-gate 		    "get_sum_line: sumline overflow (sumcount=%d, MAXSUM=%d)\n",
6607c478bd9Sstevel@tonic-gate 		    tsumcount, MAXSUM);
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	sumline[sumcount][0] = '\0';
6647c478bd9Sstevel@tonic-gate 	return (sumline[sumcount++]);
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6687c478bd9Sstevel@tonic-gate char *
get_detail_line(int off,int len)669*1ce6354aSYuri Pankov get_detail_line(int off, int len)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	if (detail_line[0]) {
67245916cd2Sjpk 		(void) printf("%s\n", detail_line);
6737c478bd9Sstevel@tonic-gate 		detail_line[0] = '\0';
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 	return (detail_line);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate /*
679605445d5Sdg199075  * This function exists to make sure that VLAN information is
680605445d5Sdg199075  * prepended to summary lines displayed.  The problem this function
681605445d5Sdg199075  * solves is how to display VLAN information while in summary mode.
682605445d5Sdg199075  * Each interpretor uses the get_sum_line and get_detail_line functions
683605445d5Sdg199075  * to get a character buffer to display information to the user.
684605445d5Sdg199075  * get_sum_line is the important one here.  Each call to get_sum_line
685605445d5Sdg199075  * gets a buffer which stores one line of information.  In summary mode,
686605445d5Sdg199075  * the last line generated is the line printed.  Instead of changing each
687605445d5Sdg199075  * interpreter to add VLAN information to the summary line, the ethernet
688605445d5Sdg199075  * interpreter changes to call this function and set an ID.  If the ID is not
689605445d5Sdg199075  * zero and snoop is in default summary mode, snoop displays the
690605445d5Sdg199075  * VLAN information at the beginning of the output line.  Otherwise,
691605445d5Sdg199075  * no VLAN information is displayed.
692605445d5Sdg199075  */
693605445d5Sdg199075 void
set_vlan_id(int id)694605445d5Sdg199075 set_vlan_id(int id)
695605445d5Sdg199075 {
696605445d5Sdg199075 	vlanid = id;
697605445d5Sdg199075 }
698605445d5Sdg199075 
699605445d5Sdg199075 /*
7007c478bd9Sstevel@tonic-gate  * Print an error.
7017c478bd9Sstevel@tonic-gate  * Works like printf (fmt string and variable args)
70245916cd2Sjpk  * except that it will substitute an error message
7037c478bd9Sstevel@tonic-gate  * for a "%m" string (like syslog) and it calls
7047c478bd9Sstevel@tonic-gate  * long_jump - it doesn't return to where it was
7057c478bd9Sstevel@tonic-gate  * called from - it goes to the last setjmp().
7067c478bd9Sstevel@tonic-gate  */
70745916cd2Sjpk /* VARARGS1 */
7087c478bd9Sstevel@tonic-gate void
pr_err(const char * fmt,...)70945916cd2Sjpk pr_err(const char *fmt, ...)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	va_list ap;
71245916cd2Sjpk 	char buf[1024], *p2;
71345916cd2Sjpk 	const char *p1;
7147c478bd9Sstevel@tonic-gate 
71545916cd2Sjpk 	(void) strcpy(buf, "snoop: ");
7167c478bd9Sstevel@tonic-gate 	p2 = buf + strlen(buf);
7177c478bd9Sstevel@tonic-gate 
71845916cd2Sjpk 	/*
71945916cd2Sjpk 	 * Note that we terminate the buffer with '\n' and '\0'.
72045916cd2Sjpk 	 */
72145916cd2Sjpk 	for (p1 = fmt; *p1 != '\0' && p2 < buf + sizeof (buf) - 2; p1++) {
7227c478bd9Sstevel@tonic-gate 		if (*p1 == '%' && *(p1+1) == 'm') {
72345916cd2Sjpk 			const char *errstr;
7247c478bd9Sstevel@tonic-gate 
72545916cd2Sjpk 			if ((errstr = strerror(errno)) != NULL) {
72645916cd2Sjpk 				*p2 = '\0';
72745916cd2Sjpk 				(void) strlcat(buf, errstr, sizeof (buf));
7287c478bd9Sstevel@tonic-gate 				p2 += strlen(p2);
7297c478bd9Sstevel@tonic-gate 			}
7307c478bd9Sstevel@tonic-gate 			p1++;
7317c478bd9Sstevel@tonic-gate 		} else {
7327c478bd9Sstevel@tonic-gate 			*p2++ = *p1;
7337c478bd9Sstevel@tonic-gate 		}
7347c478bd9Sstevel@tonic-gate 	}
7357c478bd9Sstevel@tonic-gate 	if (p2 > buf && *(p2-1) != '\n')
7367c478bd9Sstevel@tonic-gate 		*p2++ = '\n';
7377c478bd9Sstevel@tonic-gate 	*p2 = '\0';
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
74045916cd2Sjpk 	/* LINTED: E_SEC_PRINTF_VAR_FMT */
7417c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, buf, ap);
7427c478bd9Sstevel@tonic-gate 	va_end(ap);
7437c478bd9Sstevel@tonic-gate 	snoop_sigrecover(-1, NULL, NULL);	/* global error recovery */
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate /*
747c7e4935fSss150715  * Store a copy of linkname associated with the DLPI handle.
748c7e4935fSss150715  * Save errno before closing the dlpi handle so that the
749c7e4935fSss150715  * correct error value is used if 'err' is a system error.
750c7e4935fSss150715  */
751c7e4935fSss150715 void
pr_errdlpi(dlpi_handle_t dh,const char * cmd,int err)752c7e4935fSss150715 pr_errdlpi(dlpi_handle_t dh, const char *cmd, int err)
753c7e4935fSss150715 {
754c7e4935fSss150715 	int save_errno = errno;
755c7e4935fSss150715 	char linkname[DLPI_LINKNAME_MAX];
756c7e4935fSss150715 
757c7e4935fSss150715 	(void) strlcpy(linkname, dlpi_linkname(dh), sizeof (linkname));
758c7e4935fSss150715 
759c7e4935fSss150715 	dlpi_close(dh);
760c7e4935fSss150715 	errno = save_errno;
761c7e4935fSss150715 
762c7e4935fSss150715 	pr_err("%s on \"%s\": %s", cmd, linkname, dlpi_strerror(err));
763c7e4935fSss150715 }
764c7e4935fSss150715 
765c7e4935fSss150715 /*
7667c478bd9Sstevel@tonic-gate  * Ye olde usage proc
7677c478bd9Sstevel@tonic-gate  * PLEASE keep this up to date!
7687c478bd9Sstevel@tonic-gate  * Naive users *love* this stuff.
7697c478bd9Sstevel@tonic-gate  */
77045916cd2Sjpk static void
usage(void)77145916cd2Sjpk usage(void)
7727c478bd9Sstevel@tonic-gate {
7737c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\nUsage:  snoop\n");
7747c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7757c478bd9Sstevel@tonic-gate 	"\t[ -a ]			# Listen to packets on audio\n");
7767c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
777b127ac41SPhilip Kirk 	"\t[ -d link ]		# Listen on named link\n");
7787c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7797c478bd9Sstevel@tonic-gate 	"\t[ -s snaplen ]		# Truncate packets\n");
7807c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
781b127ac41SPhilip Kirk 	"\t[ -I IP interface ]		# Listen on named IP interface\n");
782b127ac41SPhilip Kirk 	(void) fprintf(stderr,
7837c478bd9Sstevel@tonic-gate 	"\t[ -c count ]		# Quit after count packets\n");
7847c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7857c478bd9Sstevel@tonic-gate 	"\t[ -P ]			# Turn OFF promiscuous mode\n");
7867c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7877c478bd9Sstevel@tonic-gate 	"\t[ -D ]			# Report dropped packets\n");
7887c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7897c478bd9Sstevel@tonic-gate 	"\t[ -S ]			# Report packet size\n");
7907c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7917c478bd9Sstevel@tonic-gate 	"\t[ -i file ]		# Read previously captured packets\n");
7927c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7937c478bd9Sstevel@tonic-gate 	"\t[ -o file ]		# Capture packets in file\n");
7947c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7957c478bd9Sstevel@tonic-gate 	"\t[ -n file ]		# Load addr-to-name table from file\n");
7967c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7977c478bd9Sstevel@tonic-gate 	"\t[ -N ]			# Create addr-to-name table\n");
7987c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
7997c478bd9Sstevel@tonic-gate 	"\t[ -t  r|a|d ]		# Time: Relative, Absolute or Delta\n");
8007c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8017c478bd9Sstevel@tonic-gate 	"\t[ -v ]			# Verbose packet display\n");
8027c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8037c478bd9Sstevel@tonic-gate 	"\t[ -V ]			# Show all summary lines\n");
8047c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8057c478bd9Sstevel@tonic-gate 	"\t[ -p first[,last] ]	# Select packet(s) to display\n");
8067c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8077c478bd9Sstevel@tonic-gate 	"\t[ -x offset[,length] ]	# Hex dump from offset for length\n");
8087c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8097c478bd9Sstevel@tonic-gate 	"\t[ -C ]			# Print packet filter code\n");
8107c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8117c478bd9Sstevel@tonic-gate 	"\t[ -q ]			# Suppress printing packet count\n");
8127c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8137c478bd9Sstevel@tonic-gate 	"\t[ -r ]			# Do not resolve address to name\n");
8147c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr,
8157c478bd9Sstevel@tonic-gate 	"\n\t[ filter expression ]\n");
8167c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\nExample:\n");
8177c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -o saved  host fred\n\n");
8187c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "\tsnoop -i saved -tr -v -p19\n");
8197c478bd9Sstevel@tonic-gate 	exit(1);
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate /*
8237c478bd9Sstevel@tonic-gate  * sdefault: default global alarm handler. Causes the current packet
8247c478bd9Sstevel@tonic-gate  * to be skipped.
8257c478bd9Sstevel@tonic-gate  */
8267c478bd9Sstevel@tonic-gate static void
sdefault(void)8277c478bd9Sstevel@tonic-gate sdefault(void)
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate 	snoop_nrecover = SNOOP_MAXRECOVER;
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate  * snoop_alarm: register or unregister an alarm handler to be called after
8347c478bd9Sstevel@tonic-gate  * s_sec seconds. Because snoop wasn't written to tolerate random signal
8357c478bd9Sstevel@tonic-gate  * delivery, periodic SIGALRM delivery (or SA_RESTART) cannot be used.
8367c478bd9Sstevel@tonic-gate  *
8377c478bd9Sstevel@tonic-gate  * s_sec argument of 0 seconds unregisters the handler.
8387c478bd9Sstevel@tonic-gate  * s_handler argument of NULL registers default handler sdefault(), or
8397c478bd9Sstevel@tonic-gate  * unregisters all signal handlers (for error recovery).
8407c478bd9Sstevel@tonic-gate  *
8417c478bd9Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
8427c478bd9Sstevel@tonic-gate  * out the signal blocking.
8437c478bd9Sstevel@tonic-gate  */
8447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8457c478bd9Sstevel@tonic-gate int
snoop_alarm(int s_sec,void (* s_handler)())8467c478bd9Sstevel@tonic-gate snoop_alarm(int s_sec, void (*s_handler)())
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	volatile time_t now;
8497c478bd9Sstevel@tonic-gate 	volatile time_t nalarm = 0;
8507c478bd9Sstevel@tonic-gate 	volatile struct snoop_handler *sh = NULL;
8517c478bd9Sstevel@tonic-gate 	volatile struct snoop_handler *hp, *tp, *next;
8527c478bd9Sstevel@tonic-gate 	volatile sigset_t s_mask;
8537c478bd9Sstevel@tonic-gate 	volatile int ret = -1;
8547c478bd9Sstevel@tonic-gate 
85545916cd2Sjpk 	(void) sigemptyset((sigset_t *)&s_mask);
85645916cd2Sjpk 	(void) sigaddset((sigset_t *)&s_mask, SIGALRM);
8577c478bd9Sstevel@tonic-gate 	if (s_sec < 0)
8587c478bd9Sstevel@tonic-gate 		return (-1);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* register an alarm handler */
8617c478bd9Sstevel@tonic-gate 	now = time(NULL);
8627c478bd9Sstevel@tonic-gate 	if (s_sec) {
8637c478bd9Sstevel@tonic-gate 		sh = malloc(sizeof (struct snoop_handler));
8647c478bd9Sstevel@tonic-gate 		sh->s_time = now + s_sec;
8657c478bd9Sstevel@tonic-gate 		if (s_handler == NULL)
8667c478bd9Sstevel@tonic-gate 			s_handler = sdefault;
8677c478bd9Sstevel@tonic-gate 		sh->s_handler = s_handler;
8687c478bd9Sstevel@tonic-gate 		sh->s_next = NULL;
8697c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8707c478bd9Sstevel@tonic-gate 		if (snoop_hp == NULL) {
8717c478bd9Sstevel@tonic-gate 			snoop_hp = snoop_tp = (struct snoop_handler *)sh;
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 			snoop_nalarm = sh->s_time;
87445916cd2Sjpk 			(void) alarm(sh->s_time - now);
8757c478bd9Sstevel@tonic-gate 		} else {
8767c478bd9Sstevel@tonic-gate 			snoop_tp->s_next = (struct snoop_handler *)sh;
8777c478bd9Sstevel@tonic-gate 			snoop_tp = (struct snoop_handler *)sh;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 			if (sh->s_time < snoop_nalarm) {
8807c478bd9Sstevel@tonic-gate 				snoop_nalarm = sh->s_time;
8817c478bd9Sstevel@tonic-gate 				(void) alarm(sh->s_time - now);
8827c478bd9Sstevel@tonic-gate 			}
8837c478bd9Sstevel@tonic-gate 		}
8847c478bd9Sstevel@tonic-gate 		(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 		return (0);
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	/* unregister an alarm handler */
8907c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, (sigset_t *)&s_mask, NULL);
8917c478bd9Sstevel@tonic-gate 	tp = (struct snoop_handler *)&snoop_hp;
8927c478bd9Sstevel@tonic-gate 	for (hp = snoop_hp; hp; hp = next) {
8937c478bd9Sstevel@tonic-gate 		next = hp->s_next;
8947c478bd9Sstevel@tonic-gate 		if (s_handler == NULL || hp->s_handler == s_handler) {
8957c478bd9Sstevel@tonic-gate 			ret = 0;
8967c478bd9Sstevel@tonic-gate 			tp->s_next = hp->s_next;
8977c478bd9Sstevel@tonic-gate 			if (snoop_tp == hp) {
8987c478bd9Sstevel@tonic-gate 				if (tp == (struct snoop_handler *)&snoop_hp)
8997c478bd9Sstevel@tonic-gate 					snoop_tp = NULL;
9007c478bd9Sstevel@tonic-gate 				else
9017c478bd9Sstevel@tonic-gate 					snoop_tp = (struct snoop_handler *)tp;
9027c478bd9Sstevel@tonic-gate 			}
9037c478bd9Sstevel@tonic-gate 			free((void *)hp);
9047c478bd9Sstevel@tonic-gate 		} else {
9057c478bd9Sstevel@tonic-gate 			if (nalarm == 0 || nalarm > hp->s_time)
9067c478bd9Sstevel@tonic-gate 				nalarm = now < hp->s_time ? hp->s_time :
9077c478bd9Sstevel@tonic-gate 				    now + 1;
9087c478bd9Sstevel@tonic-gate 			tp = hp;
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 	/*
9127c478bd9Sstevel@tonic-gate 	 * Stop or adjust timer
9137c478bd9Sstevel@tonic-gate 	 */
9147c478bd9Sstevel@tonic-gate 	if (snoop_hp == NULL) {
9157c478bd9Sstevel@tonic-gate 		snoop_nalarm = 0;
9167c478bd9Sstevel@tonic-gate 		(void) alarm(0);
9177c478bd9Sstevel@tonic-gate 	} else if (nalarm > 0 && nalarm < snoop_nalarm) {
9187c478bd9Sstevel@tonic-gate 		snoop_nalarm = nalarm;
9197c478bd9Sstevel@tonic-gate 		(void) alarm(nalarm - now);
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_UNBLOCK, (sigset_t *)&s_mask, NULL);
9237c478bd9Sstevel@tonic-gate 	return (ret);
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate  * snoop_recover: reset snoop's output area, and any internal variables,
9287c478bd9Sstevel@tonic-gate  * to allow continuation.
9297c478bd9Sstevel@tonic-gate  * XXX: make this an interface such that each interpreter can
9307c478bd9Sstevel@tonic-gate  * register a reset routine.
9317c478bd9Sstevel@tonic-gate  */
9327c478bd9Sstevel@tonic-gate void
snoop_recover(void)9337c478bd9Sstevel@tonic-gate snoop_recover(void)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	int i;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/* Error recovery: reset output_area and associated variables */
9387c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXSUM; i++)
9397c478bd9Sstevel@tonic-gate 		sumline[i][0] = '\0';
9407c478bd9Sstevel@tonic-gate 	detail_line[0] = '\0';
9417c478bd9Sstevel@tonic-gate 	line[0] = '\0';
9427c478bd9Sstevel@tonic-gate 	encap[0] = '\0';
9437c478bd9Sstevel@tonic-gate 	sumcount = 0;
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/* stacking/unstacking cannot be relied upon */
9467c478bd9Sstevel@tonic-gate 	encap_levels = 0;
9477c478bd9Sstevel@tonic-gate 	total_encap_levels = 1;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	/* remove any pending timeouts */
9507c478bd9Sstevel@tonic-gate 	(void) snoop_alarm(0, NULL);
9517c478bd9Sstevel@tonic-gate }
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate /*
9547c478bd9Sstevel@tonic-gate  * snoop_sigrecover: global sigaction routine to manage recovery
9557c478bd9Sstevel@tonic-gate  * from catastrophic interpreter failures while interpreting
9567c478bd9Sstevel@tonic-gate  * corrupt trace files/packets. SIGALRM timeouts, program errors,
9577c478bd9Sstevel@tonic-gate  * and user termination are all handled. In the case of a corrupt
9587c478bd9Sstevel@tonic-gate  * packet or confused interpreter, the packet will be skipped, and
9597c478bd9Sstevel@tonic-gate  * execution will continue in scan().
9607c478bd9Sstevel@tonic-gate  *
9617c478bd9Sstevel@tonic-gate  * Global alarm handling (see snoop_alarm()) is managed here.
9627c478bd9Sstevel@tonic-gate  *
9637c478bd9Sstevel@tonic-gate  * Variables must be volatile to force the compiler to not optimize
9647c478bd9Sstevel@tonic-gate  * out the signal blocking.
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
96745916cd2Sjpk static void
snoop_sigrecover(int sig,siginfo_t * info,void * p)9687c478bd9Sstevel@tonic-gate snoop_sigrecover(int sig, siginfo_t *info, void *p)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate 	volatile time_t now;
9717c478bd9Sstevel@tonic-gate 	volatile time_t nalarm = 0;
9727c478bd9Sstevel@tonic-gate 	volatile struct snoop_handler *hp;
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	/*
9757c478bd9Sstevel@tonic-gate 	 * Invoke any registered alarms. This involves first calculating
9767c478bd9Sstevel@tonic-gate 	 * the time for the next alarm, setting it up, then progressing
9777c478bd9Sstevel@tonic-gate 	 * through handler invocations. Note that since handlers may
9787c478bd9Sstevel@tonic-gate 	 * use siglongjmp(), in the worst case handlers may be serviced
9797c478bd9Sstevel@tonic-gate 	 * at a later time.
9807c478bd9Sstevel@tonic-gate 	 */
9817c478bd9Sstevel@tonic-gate 	if (sig == SIGALRM) {
9827c478bd9Sstevel@tonic-gate 		now = time(NULL);
9837c478bd9Sstevel@tonic-gate 		/* Calculate next alarm time */
9847c478bd9Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
9857c478bd9Sstevel@tonic-gate 			if (hp->s_time) {
9867c478bd9Sstevel@tonic-gate 				if ((hp->s_time - now) > 0) {
9877c478bd9Sstevel@tonic-gate 					if (nalarm == 0 || nalarm > hp->s_time)
9887c478bd9Sstevel@tonic-gate 						nalarm = now < hp->s_time ?
9897c478bd9Sstevel@tonic-gate 						    hp->s_time : now + 1;
9907c478bd9Sstevel@tonic-gate 				}
9917c478bd9Sstevel@tonic-gate 			}
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 		/* Setup next alarm */
9947c478bd9Sstevel@tonic-gate 		if (nalarm) {
9957c478bd9Sstevel@tonic-gate 			snoop_nalarm = nalarm;
99645916cd2Sjpk 			(void) alarm(nalarm - now);
9977c478bd9Sstevel@tonic-gate 		} else {
9987c478bd9Sstevel@tonic-gate 			snoop_nalarm = 0;
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		/* Invoke alarm handlers (may not return) */
10027c478bd9Sstevel@tonic-gate 		for (hp = snoop_hp; hp; hp = hp->s_next) {
10037c478bd9Sstevel@tonic-gate 			if (hp->s_time) {
10047c478bd9Sstevel@tonic-gate 				if ((now - hp->s_time) >= 0) {
10057c478bd9Sstevel@tonic-gate 					hp->s_time = 0;	/* only invoke once */
10067c478bd9Sstevel@tonic-gate 					if (hp->s_handler)
10077c478bd9Sstevel@tonic-gate 						hp->s_handler();
10087c478bd9Sstevel@tonic-gate 				}
10097c478bd9Sstevel@tonic-gate 			}
10107c478bd9Sstevel@tonic-gate 		}
10117c478bd9Sstevel@tonic-gate 	} else {
10127c478bd9Sstevel@tonic-gate 		snoop_nrecover++;
10137c478bd9Sstevel@tonic-gate 	}
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	/*
10167c478bd9Sstevel@tonic-gate 	 * Exit if a signal has occurred after snoop has begun the process
10177c478bd9Sstevel@tonic-gate 	 * of quitting.
10187c478bd9Sstevel@tonic-gate 	 */
10197c478bd9Sstevel@tonic-gate 	if (quitting)
10207c478bd9Sstevel@tonic-gate 		exit(1);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	/*
10237c478bd9Sstevel@tonic-gate 	 * If an alarm handler has timed out, and snoop_nrecover has
10247c478bd9Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, skip to the next packet.
10257c478bd9Sstevel@tonic-gate 	 *
10267c478bd9Sstevel@tonic-gate 	 * If any other signal has occurred, and snoop_nrecover has
10277c478bd9Sstevel@tonic-gate 	 * reached SNOOP_MAXRECOVER, give up.
10287c478bd9Sstevel@tonic-gate 	 */
10297c478bd9Sstevel@tonic-gate 	if (sig == SIGALRM) {
10307c478bd9Sstevel@tonic-gate 		if (ioctl(STDOUT_FILENO, I_CANPUT, 0) == 0) {
10317c478bd9Sstevel@tonic-gate 			/*
10327c478bd9Sstevel@tonic-gate 			 * We've stalled on output, which is not a critical
10337c478bd9Sstevel@tonic-gate 			 * failure.  Reset the recovery counter so we do not
10347c478bd9Sstevel@tonic-gate 			 * consider this a persistent failure, and return so
10357c478bd9Sstevel@tonic-gate 			 * we do not skip this packet.
10367c478bd9Sstevel@tonic-gate 			 */
10377c478bd9Sstevel@tonic-gate 			snoop_nrecover = 0;
10387c478bd9Sstevel@tonic-gate 			return;
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 		if (snoop_nrecover >= SNOOP_MAXRECOVER) {
104145916cd2Sjpk 			(void) fprintf(stderr,
10427c478bd9Sstevel@tonic-gate 			    "snoop: WARNING: skipping from packet %d\n",
10437c478bd9Sstevel@tonic-gate 			    count);
10447c478bd9Sstevel@tonic-gate 			snoop_nrecover = 0;
10457c478bd9Sstevel@tonic-gate 		} else {
10467c478bd9Sstevel@tonic-gate 			/* continue trying */
10477c478bd9Sstevel@tonic-gate 			return;
10487c478bd9Sstevel@tonic-gate 		}
10497c478bd9Sstevel@tonic-gate 	} else if (snoop_nrecover >= SNOOP_MAXRECOVER) {
105045916cd2Sjpk 		(void) fprintf(stderr,
10517c478bd9Sstevel@tonic-gate 		    "snoop: ERROR: cannot recover from packet %d\n", count);
10527c478bd9Sstevel@tonic-gate 		exit(1);
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate #ifdef DEBUG
105645916cd2Sjpk 	(void) fprintf(stderr, "snoop_sigrecover(%d, %p, %p)\n", sig, info, p);
10577c478bd9Sstevel@tonic-gate #endif /* DEBUG */
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/*
10607c478bd9Sstevel@tonic-gate 	 * Prepare to quit. This allows final processing to occur
10617c478bd9Sstevel@tonic-gate 	 * after first terminal interruption.
10627c478bd9Sstevel@tonic-gate 	 */
10637c478bd9Sstevel@tonic-gate 	if (sig == SIGTERM || sig == SIGHUP || sig == SIGINT) {
10647c478bd9Sstevel@tonic-gate 		quitting = 1;
10657c478bd9Sstevel@tonic-gate 		return;
10667c478bd9Sstevel@tonic-gate 	} else if (sig != -1 && sig != SIGALRM) {
10677c478bd9Sstevel@tonic-gate 		/* Inform user that snoop has taken a fault */
106845916cd2Sjpk 		(void) fprintf(stderr,
106945916cd2Sjpk 		    "WARNING: received signal %d from packet %d\n",
10707c478bd9Sstevel@tonic-gate 		    sig, count);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	/* Reset interpreter variables */
10747c478bd9Sstevel@tonic-gate 	snoop_recover();
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate 	/* Continue in scan() with the next packet */
10777c478bd9Sstevel@tonic-gate 	siglongjmp(jmp_env, 1);
10787c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
10797c478bd9Sstevel@tonic-gate }
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate /*
10827c478bd9Sstevel@tonic-gate  * Protected malloc for global error recovery: prepare for interpreter
10837c478bd9Sstevel@tonic-gate  * failures with corrupted packets or confused interpreters.  Dynamically
10847c478bd9Sstevel@tonic-gate  * allocate `nbytes' bytes, and sandwich it between two PROT_NONE pages to
10857c478bd9Sstevel@tonic-gate  * catch writes outside of the allocated region.
10867c478bd9Sstevel@tonic-gate  */
10877c478bd9Sstevel@tonic-gate static char *
protmalloc(size_t nbytes)10887c478bd9Sstevel@tonic-gate protmalloc(size_t nbytes)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	caddr_t start;
10917c478bd9Sstevel@tonic-gate 	int psz = sysconf(_SC_PAGESIZE);
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 	nbytes = P2ROUNDUP(nbytes, psz);
10947c478bd9Sstevel@tonic-gate 	start = mmap(NULL, nbytes + psz * 2, PROT_READ|PROT_WRITE,
10957c478bd9Sstevel@tonic-gate 	    MAP_PRIVATE|MAP_ANON, -1, 0);
10967c478bd9Sstevel@tonic-gate 	if (start == MAP_FAILED) {
10977c478bd9Sstevel@tonic-gate 		perror("Error: protmalloc: mmap");
10987c478bd9Sstevel@tonic-gate 		return (NULL);
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 	assert(IS_P2ALIGNED(start, psz));
11017c478bd9Sstevel@tonic-gate 	if (mprotect(start, 1, PROT_NONE) == -1)
11027c478bd9Sstevel@tonic-gate 		perror("Warning: mprotect");
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	start += psz;
11057c478bd9Sstevel@tonic-gate 	if (mprotect(start + nbytes, 1, PROT_NONE) == -1)
11067c478bd9Sstevel@tonic-gate 		perror("Warning: mprotect");
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	return (start);
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate /*
11127c478bd9Sstevel@tonic-gate  * resetperm - reduce security vulnerabilities by resetting
11137c478bd9Sstevel@tonic-gate  * owner/group/permissions. Always attempt setuid() - if we have
11147c478bd9Sstevel@tonic-gate  * permission to drop our privilege level, do so.
11157c478bd9Sstevel@tonic-gate  */
11167c478bd9Sstevel@tonic-gate void
resetperm(void)11177c478bd9Sstevel@tonic-gate resetperm(void)
11187c478bd9Sstevel@tonic-gate {
11197c478bd9Sstevel@tonic-gate 	if (geteuid() == 0) {
11207c478bd9Sstevel@tonic-gate 		(void) setgid(GID_NOBODY);
11217c478bd9Sstevel@tonic-gate 		(void) setuid(UID_NOBODY);
11227c478bd9Sstevel@tonic-gate 	}
11237c478bd9Sstevel@tonic-gate }
1124