tcp_debug.c revision 169350
1/*- 2 * Copyright (c) 1982, 1986, 1993 3 * The Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93 31 * $FreeBSD: head/sys/netinet/tcp_debug.c 169350 2007-05-07 14:05:23Z rwatson $ 32 */ 33 34#include "opt_inet.h" 35#include "opt_inet6.h" 36#include "opt_tcpdebug.h" 37 38#ifndef INET 39#error The option TCPDEBUG requires option INET. 40#endif 41 42#ifdef TCPDEBUG 43/* load symbolic names */ 44#define PRUREQUESTS 45#define TCPSTATES 46#define TCPTIMERS 47#define TANAMES 48#endif 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/kernel.h> 53#include <sys/lock.h> 54#include <sys/mbuf.h> 55#include <sys/mutex.h> 56#include <sys/protosw.h> 57#include <sys/socket.h> 58 59#include <netinet/in.h> 60#include <netinet/in_systm.h> 61#include <netinet/ip.h> 62#ifdef INET6 63#include <netinet/ip6.h> 64#endif 65#include <netinet/ip_var.h> 66#include <netinet/tcp.h> 67#include <netinet/tcp_fsm.h> 68#include <netinet/tcp_timer.h> 69#include <netinet/tcp_var.h> 70#include <netinet/tcpip.h> 71#include <netinet/tcp_debug.h> 72 73#ifdef TCPDEBUG 74static int tcpconsdebug = 0; 75#endif 76 77/* 78 * Global ring buffer of TCP debugging state. Each entry captures a snapshot 79 * of TCP connection state at any given moment. tcp_debx addresses at the 80 * next available slot. There is no explicit export of this data structure; 81 * it will be read via /dev/kmem by debugging tools. 82 */ 83static struct tcp_debug tcp_debug[TCP_NDEBUG]; 84static int tcp_debx; 85 86/* 87 * All global state is protected by tcp_debug_mtx; tcp_trace() is split into 88 * two parts, one of which saves connection and other state into the global 89 * array (locked by tcp_debug_mtx). 90 */ 91struct mtx tcp_debug_mtx; 92MTX_SYSINIT(tcp_debug_mtx, &tcp_debug_mtx, "tcp_debug_mtx", MTX_DEF); 93 94/* 95 * Save TCP state at a given moment; optionally, both tcpcb and TCP packet 96 * header state will be saved. 97 */ 98void 99tcp_trace(short act, short ostate, struct tcpcb *tp, void *ipgen, 100 struct tcphdr *th, int req) 101{ 102#ifdef INET6 103 int isipv6; 104#endif /* INET6 */ 105 tcp_seq seq, ack; 106 int len, flags; 107 struct tcp_debug *td; 108 109 mtx_lock(&tcp_debug_mtx); 110 td = &tcp_debug[tcp_debx++]; 111 if (tcp_debx == TCP_NDEBUG) 112 tcp_debx = 0; 113 bzero(td, sizeof(*td)); 114#ifdef INET6 115 isipv6 = (ipgen != NULL && ((struct ip *)ipgen)->ip_v == 6) ? 1 : 0; 116#endif /* INET6 */ 117 td->td_family = 118#ifdef INET6 119 (isipv6 != 0) ? AF_INET6 : 120#endif 121 AF_INET; 122 td->td_time = iptime(); 123 td->td_act = act; 124 td->td_ostate = ostate; 125 td->td_tcb = (caddr_t)tp; 126 if (tp != NULL) 127 td->td_cb = *tp; 128 if (ipgen != NULL) { 129 switch (td->td_family) { 130 case AF_INET: 131 bcopy(ipgen, &td->td_ti.ti_i, sizeof(td->td_ti.ti_i)); 132 break; 133#ifdef INET6 134 case AF_INET6: 135 bcopy(ipgen, td->td_ip6buf, sizeof(td->td_ip6buf)); 136 break; 137#endif 138 } 139 } 140 if (th != NULL) { 141 switch (td->td_family) { 142 case AF_INET: 143 td->td_ti.ti_t = *th; 144 break; 145#ifdef INET6 146 case AF_INET6: 147 td->td_ti6.th = *th; 148 break; 149#endif 150 } 151 } 152 td->td_req = req; 153 mtx_unlock(&tcp_debug_mtx); 154#ifdef TCPDEBUG 155 if (tcpconsdebug == 0) 156 return; 157 if (tp != NULL) 158 printf("%p %s:", tp, tcpstates[ostate]); 159 else 160 printf("???????? "); 161 printf("%s ", tanames[act]); 162 switch (act) { 163 case TA_INPUT: 164 case TA_OUTPUT: 165 case TA_DROP: 166 if (ipgen == NULL || th == NULL) 167 break; 168 seq = th->th_seq; 169 ack = th->th_ack; 170 len = 171#ifdef INET6 172 isipv6 ? ((struct ip6_hdr *)ipgen)->ip6_plen : 173#endif 174 ((struct ip *)ipgen)->ip_len; 175 if (act == TA_OUTPUT) { 176 seq = ntohl(seq); 177 ack = ntohl(ack); 178 len = ntohs((u_short)len); 179 } 180 if (act == TA_OUTPUT) 181 len -= sizeof (struct tcphdr); 182 if (len) 183 printf("[%x..%x)", seq, seq+len); 184 else 185 printf("%x", seq); 186 printf("@%x, urp=%x", ack, th->th_urp); 187 flags = th->th_flags; 188 if (flags) { 189 char *cp = "<"; 190#define pf(f) { \ 191 if (th->th_flags & TH_##f) { \ 192 printf("%s%s", cp, #f); \ 193 cp = ","; \ 194 } \ 195} 196 pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG); 197 printf(">"); 198 } 199 break; 200 201 case TA_USER: 202 printf("%s", prurequests[req&0xff]); 203 if ((req & 0xff) == PRU_SLOWTIMO) 204 printf("<%s>", tcptimers[req>>8]); 205 break; 206 } 207 if (tp != NULL) 208 printf(" -> %s", tcpstates[tp->t_state]); 209 /* print out internal state of tp !?! */ 210 printf("\n"); 211 if (tp == NULL) 212 return; 213 printf( 214 "\trcv_(nxt,wnd,up) (%lx,%lx,%lx) snd_(una,nxt,max) (%lx,%lx,%lx)\n", 215 (u_long)tp->rcv_nxt, tp->rcv_wnd, (u_long)tp->rcv_up, 216 (u_long)tp->snd_una, (u_long)tp->snd_nxt, (u_long)tp->snd_max); 217 printf("\tsnd_(wl1,wl2,wnd) (%lx,%lx,%lx)\n", 218 (u_long)tp->snd_wl1, (u_long)tp->snd_wl2, tp->snd_wnd); 219#endif /* TCPDEBUG */ 220} 221