/* $NetBSD: trsp.c,v 1.12 2006/03/30 21:05:07 dsl Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #ifndef lint __COPYRIGHT( "@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n"); #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)trsp.c 8.1 (Berkeley) 6/6/93"; #else __RCSID("$NetBSD: trsp.c,v 1.12 2006/03/30 21:05:07 dsl Exp $"); #endif #endif /* not lint */ #include #include #include #include #include #define PRUREQUESTS #include #include #include #define TCPSTATES #include #define TCPTIMERS #include #include #include #include #include #include #include #include #include #define SANAMES #include #include #include #include #include #include #include #include #include #include #include #include u_int32_t ntime; int sflag; int tflag; int jflag; int aflag; int zflag; struct nlist nl[] = { #define N_SPP_DEBUG 0 { "_spp_debug" }, #define N_SPP_DEBX 1 { "_spp_debx" }, { NULL }, }; struct spp_debug spp_debug[SPP_NDEBUG]; caddr_t spp_pcbs[SPP_NDEBUG]; int spp_debx; kvm_t *kd; int main(int, char *[]); void dotrace(caddr_t); int numeric(const void *, const void *); void spp_trace(short, short, struct sppcb *, struct sppcb *, struct spidp *, int); void usage(void); int main(int argc, char *argv[]) { int ch, i, npcbs = 0, use_sysctl; char *system, *core, *cp, errbuf[_POSIX2_LINE_MAX]; unsigned long l; system = core = NULL; while ((ch = getopt(argc, argv, "azstjp:N:M:")) != -1) { switch (ch) { case 'a': ++aflag; break; case 'z': ++zflag; break; case 's': ++sflag; break; case 't': ++tflag; break; case 'j': ++jflag; break; case 'p': if (npcbs >= SPP_NDEBUG) errx(1, "too many pcbs specified"); errno = 0; cp = NULL; l = strtoul(optarg, &cp, 16); spp_pcbs[npcbs] = (caddr_t)l; if (*optarg == '\0' || *cp != '\0' || errno || (unsigned long)spp_pcbs[npcbs] != l) errx(1, "invalid address: %s", optarg); npcbs++; break; case 'N': system = optarg; break; case 'M': core = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc) usage(); use_sysctl = (system == NULL && core == NULL); if (use_sysctl) { size_t lenx = sizeof(spp_debx); size_t lend = sizeof(spp_debug); if (sysctlbyname("net.ns.spp.debx", &spp_debx, &lenx, NULL, 0) == -1) err(1, "net.ns.spp.debx"); if (sysctlbyname("net.ns.spp.debug", &spp_debug, &lend, NULL, 0) == -1) err(1, "net.ns.spp.debug"); } else { kd = kvm_openfiles(system, core, NULL, zflag ? O_RDWR : O_RDONLY, errbuf); if (kd == NULL) errx(1, "can't open kmem: %s", errbuf); if (kvm_nlist(kd, nl)) errx(2, "%s: no namelist", system); if (kvm_read(kd, nl[N_SPP_DEBX].n_value, &spp_debx, sizeof(spp_debx)) != sizeof(spp_debx)) errx(3, "spp_debx: %s", kvm_geterr(kd)); if (kvm_read(kd, nl[N_SPP_DEBUG].n_value, spp_debug, sizeof(spp_debug)) != sizeof(spp_debug)) errx(3, "spp_debug: %s", kvm_geterr(kd)); } printf("spp_debx=%d\n", spp_debx); /* * Here, we just want to clear out the old trace data and start over. */ if (zflag) { spp_debx = 0; (void) memset(spp_debug, 0, sizeof(spp_debug)); if (use_sysctl) { if (sysctlbyname("net.ns.spp.debx", NULL, 0, &spp_debx, sizeof(spp_debx)) == -1) err(1, "write spp_debx"); if (sysctlbyname("net.ns.spp.debug", NULL, 0, &spp_debug, sizeof(spp_debug)) == -1) err(1, "write spp_debug"); } else { if (kvm_write(kd, nl[N_SPP_DEBX].n_value, &spp_debx, sizeof(spp_debx)) != sizeof(spp_debx)) errx(4, "write spp_debx: %s", kvm_geterr(kd)); if (kvm_write(kd, nl[N_SPP_DEBUG].n_value, spp_debug, sizeof(spp_debug)) != sizeof(spp_debug)) errx(4, "write spp_debug: %s", kvm_geterr(kd)); } exit(0); } /* * If no control blocks have been specified, figure * out how many distinct one we have and summarize * them in spp_pcbs for sorting the trace records * below. */ if (npcbs == 0) { for (i = 0; i < SPP_NDEBUG; i++) { struct spp_debug *sd = &spp_debug[i]; int j; if (sd->sd_cb == 0) continue; for (j = 0; j < npcbs; j++) if (spp_pcbs[j] == sd->sd_cb) break; if (j >= npcbs) spp_pcbs[npcbs++] = sd->sd_cb; } } qsort(spp_pcbs, npcbs, sizeof (caddr_t), numeric); if (jflag) { cp = ""; for (i = 0; i < npcbs; i++) { printf("%s%lx", cp, (long)spp_pcbs[i]); cp = ", "; } if (*cp) putchar('\n'); } else { for (i = 0; i < npcbs; i++) { printf("\n%lx:\n", (long)spp_pcbs[i]); dotrace(spp_pcbs[i]); } } exit(0); } void dotrace(caddr_t sppcb) { struct spp_debug *sd; int i; for (i = spp_debx % SPP_NDEBUG; i < SPP_NDEBUG; i++) { sd = &spp_debug[i]; if (sppcb && sd->sd_cb != sppcb) continue; ntime = ntohl(sd->sd_time); spp_trace(sd->sd_act, sd->sd_ostate, (struct sppcb *)sd->sd_cb, &sd->sd_sp, &sd->sd_si, sd->sd_req); } for (i = 0; i < spp_debx % SPP_NDEBUG; i++) { sd = &spp_debug[i]; if (sppcb && sd->sd_cb != sppcb) continue; ntime = ntohl(sd->sd_time); spp_trace(sd->sd_act, sd->sd_ostate, (struct sppcb *)sd->sd_cb, &sd->sd_sp, &sd->sd_si, sd->sd_req); } } int numeric(const void *v1, const void *v2) { const caddr_t *c1 = v1; const caddr_t *c2 = v2; int rv; if (*c1 < *c2) rv = -1; else if (*c1 > *c2) rv = 1; else rv = 0; return (rv); } void spp_trace(short act, short ostate, struct sppcb *asp, struct sppcb *sp, struct spidp *si, int req) { u_int16_t seq, ack, len, alo; int flags; char *cp; if (ostate >= TCP_NSTATES) ostate = 0; if (act > SA_DROP) act = SA_DROP; printf("\n"); printf("%03d %s:%s", (ntime/10) % 1000, tcpstates[ostate], sanames[act]); if (si != 0) { seq = si->si_seq; ack = si->si_ack; alo = si->si_alo; len = si->si_len; switch (act) { case SA_RESPOND: case SA_OUTPUT: NTOHS(seq); NTOHS(ack); NTOHS(alo); NTOHS(len); case SA_INPUT: case SA_DROP: if (aflag) printf("\n\tsna=%s\tdna=%s", ns_ntoa(si->si_sna), ns_ntoa(si->si_dna)); printf("\n\t"); #define p1(name, f) { \ printf("%s = %x, ", name, f); \ } p1("seq", seq); p1("ack", ack); p1("alo", alo); p1("len", len); flags = si->si_cc; printf("flags=%x", flags); #define pf(name, f) { \ if (flags & f) { \ printf("%s%s", cp, name); \ cp = ","; \ } \ } if (flags) { cp = "<"; pf("SP_SP", SP_SP); pf("SP_SA", SP_SA); pf("SP_OB", SP_OB); pf("SP_EM", SP_EM); printf(">"); } printf(", "); #define p2(name, f) { \ printf("%s = %x, ", name, f); \ } p2("sid", si->si_sid); p2("did", si->si_did); p2("dt", si->si_dt); printf("\n\tsna=%s\tdna=%s", ns_ntoa(si->si_sna), ns_ntoa(si->si_dna)); } } if(act == SA_USER) { printf("\treq=%s", prurequests[req&0xff]); if ((req & 0xff) == PRU_SLOWTIMO) printf("<%s>", tcptimers[req>>8]); } printf(" -> %s\n", tcpstates[sp->s_state]); /* print out internal state of sp !?! */ #define p3(name, f) { \ printf("%s = %x, ", name, f); \ } if (sflag) { printf("\t"); p3("rack", sp->s_rack); p3("ralo", sp->s_ralo); p3("smax", sp->s_smax); p3("snxt", sp->s_snxt); p3("flags", sp->s_flags); #undef pf #define pf(name, f) { \ if (flags & f) { \ printf("%s%s", cp, name); \ cp = ","; \ } \ } flags = sp->s_flags; if (flags || sp->s_oobflags) { cp = "<"; pf("ACKNOW", SF_ACKNOW); pf("DELACK", SF_DELACK); pf("HI", SF_HI); pf("HO", SF_HO); pf("PI", SF_PI); pf("WIN", SF_WIN); pf("RXT", SF_RXT); pf("RVD", SF_RVD); flags = sp->s_oobflags; pf("SOOB", SF_SOOB); pf("IOOB", SF_IOOB); printf(">"); } } /* print out timers? */ if (tflag) { int i; cp = "\t"; printf("\n\tTIMERS: "); p3("idle", sp->s_idle); p3("force", sp->s_force); p3("rtseq", sp->s_rtseq); for (i = 0; i < TCPT_NTIMERS; i++) { if (sp->s_timer[i] == 0) continue; printf("%s%s=%d", cp, tcptimers[i], sp->s_timer[i]); if (i == TCPT_REXMT) printf(" (s_rxtshft=%d)", sp->s_rxtshift); cp = ", "; } if (*cp != '\t') putchar('\n'); } } void usage(void) { fprintf(stderr, "usage: %s [-azstj] [-p hex-address]" " [-N system] [-M core]\n", getprogname()); exit(1); }