tcp_debug.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)tcp_debug.c 8.1 (Berkeley) 6/10/93 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: stable/11/sys/netinet/tcp_debug.c 330897 2018-03-14 03:19:51Z eadler $"); 37 38#include "opt_inet.h" 39#include "opt_inet6.h" 40#include "opt_tcpdebug.h" 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#ifdef INET 123 td->td_time = iptime(); 124#endif 125 td->td_act = act; 126 td->td_ostate = ostate; 127 td->td_tcb = (caddr_t)tp; 128 if (tp != NULL) 129 td->td_cb = *tp; 130 if (ipgen != NULL) { 131 switch (td->td_family) { 132#ifdef INET 133 case AF_INET: 134 bcopy(ipgen, &td->td_ti.ti_i, sizeof(td->td_ti.ti_i)); 135 break; 136#endif 137#ifdef INET6 138 case AF_INET6: 139 bcopy(ipgen, td->td_ip6buf, sizeof(td->td_ip6buf)); 140 break; 141#endif 142 } 143 } 144 if (th != NULL) { 145 switch (td->td_family) { 146#ifdef INET 147 case AF_INET: 148 td->td_ti.ti_t = *th; 149 break; 150#endif 151#ifdef INET6 152 case AF_INET6: 153 td->td_ti6.th = *th; 154 break; 155#endif 156 } 157 } 158 td->td_req = req; 159 mtx_unlock(&tcp_debug_mtx); 160#ifdef TCPDEBUG 161 if (tcpconsdebug == 0) 162 return; 163 if (tp != NULL) 164 printf("%p %s:", tp, tcpstates[ostate]); 165 else 166 printf("???????? "); 167 printf("%s ", tanames[act]); 168 switch (act) { 169 case TA_INPUT: 170 case TA_OUTPUT: 171 case TA_DROP: 172 if (ipgen == NULL || th == NULL) 173 break; 174 seq = th->th_seq; 175 ack = th->th_ack; 176 len = 177#ifdef INET6 178 isipv6 ? ntohs(((struct ip6_hdr *)ipgen)->ip6_plen) : 179#endif 180 ntohs(((struct ip *)ipgen)->ip_len); 181 if (act == TA_OUTPUT) { 182 seq = ntohl(seq); 183 ack = ntohl(ack); 184 } 185 if (act == TA_OUTPUT) 186 len -= sizeof (struct tcphdr); 187 if (len) 188 printf("[%x..%x)", seq, seq+len); 189 else 190 printf("%x", seq); 191 printf("@%x, urp=%x", ack, th->th_urp); 192 flags = th->th_flags; 193 if (flags) { 194 char *cp = "<"; 195#define pf(f) { \ 196 if (th->th_flags & TH_##f) { \ 197 printf("%s%s", cp, #f); \ 198 cp = ","; \ 199 } \ 200} 201 pf(SYN); pf(ACK); pf(FIN); pf(RST); pf(PUSH); pf(URG); 202 printf(">"); 203 } 204 break; 205 206 case TA_USER: 207 printf("%s", prurequests[req&0xff]); 208 if ((req & 0xff) == PRU_SLOWTIMO) 209 printf("<%s>", tcptimers[req>>8]); 210 break; 211 } 212 if (tp != NULL) 213 printf(" -> %s", tcpstates[tp->t_state]); 214 /* print out internal state of tp !?! */ 215 printf("\n"); 216 if (tp == NULL) 217 return; 218 printf( 219 "\trcv_(nxt,wnd,up) (%lx,%lx,%lx) snd_(una,nxt,max) (%lx,%lx,%lx)\n", 220 (u_long)tp->rcv_nxt, tp->rcv_wnd, (u_long)tp->rcv_up, 221 (u_long)tp->snd_una, (u_long)tp->snd_nxt, (u_long)tp->snd_max); 222 printf("\tsnd_(wl1,wl2,wnd) (%lx,%lx,%lx)\n", 223 (u_long)tp->snd_wl1, (u_long)tp->snd_wl2, tp->snd_wnd); 224#endif /* TCPDEBUG */ 225} 226