1*25202Skarels #ifdef RCSIDENT 2*25202Skarels static char rcsident[] = "$Header: tcp_input.c,v 1.25 85/07/31 09:33:47 walsh Exp $"; 3*25202Skarels #endif 4*25202Skarels 5*25202Skarels #include "../h/param.h" 6*25202Skarels #include "../h/dir.h" 7*25202Skarels #include "../h/user.h" 8*25202Skarels #include "../h/kernel.h" 9*25202Skarels #include "../h/inode.h" 10*25202Skarels #include "../h/mbuf.h" 11*25202Skarels #include "../h/socket.h" 12*25202Skarels #include "../h/socketvar.h" 13*25202Skarels #include "../h/syslog.h" 14*25202Skarels 15*25202Skarels #include "../net/if.h" 16*25202Skarels #include "../net/route.h" 17*25202Skarels 18*25202Skarels #include "../bbnnet/in.h" 19*25202Skarels #include "../bbnnet/net.h" 20*25202Skarels #include "../bbnnet/in_pcb.h" 21*25202Skarels #include "../bbnnet/in_var.h" 22*25202Skarels #include "../bbnnet/fsm.h" 23*25202Skarels #include "../bbnnet/tcp.h" 24*25202Skarels #include "../bbnnet/seq.h" 25*25202Skarels #include "../bbnnet/ip.h" 26*25202Skarels #include "../bbnnet/fsmdef.h" 27*25202Skarels #include "../bbnnet/macros.h" 28*25202Skarels #include "../bbnnet/nopcb.h" 29*25202Skarels #ifdef HMPTRAPS 30*25202Skarels #include "../bbnnet/hmp_traps.h" 31*25202Skarels #endif 32*25202Skarels 33*25202Skarels #ifdef HMPTRAPS 34*25202Skarels #define HMP_TRAP(a,b,c) hmp_trap(a,b,c) 35*25202Skarels #else 36*25202Skarels #define HMP_TRAP(a,b,c) 37*25202Skarels #endif 38*25202Skarels 39*25202Skarels extern int nosum; 40*25202Skarels extern struct inpcb tcp; 41*25202Skarels 42*25202Skarels /* 43*25202Skarels * net preproc (66,67,68,69,70,71,72,73,74,75,76) 44*25202Skarels * 45*25202Skarels * macro form of former function netprepr() 46*25202Skarels * 47*25202Skarels * tp valid tcpcb 48*25202Skarels * n valid th 49*25202Skarels * inp valid inpcb ( == tp->t_in_pcb ) 50*25202Skarels */ 51*25202Skarels #define NETPREPR(tp, n, inp, retval) \ 52*25202Skarels { \ 53*25202Skarels retval = (-1); /* assume bad */ \ 54*25202Skarels /* tell caller to eat segment (unacceptable) */ \ 55*25202Skarels \ 56*25202Skarels switch (tp->t_state) { \ 57*25202Skarels case LISTEN: \ 58*25202Skarels /* Ignore resets, ACKs cause resets, must have SYN. */ \ 59*25202Skarels if (n->t_flags&T_RST) \ 60*25202Skarels break; \ 61*25202Skarels else if (n->t_flags&T_ACK) \ 62*25202Skarels send_rst(tp, n); \ 63*25202Skarels else if (n->t_flags&T_SYN) \ 64*25202Skarels retval = SAME; \ 65*25202Skarels break; \ 66*25202Skarels \ 67*25202Skarels case SYN_SENT: \ 68*25202Skarels /* Bad ACKs cause resets, good resets close, must have SYN. */ \ 69*25202Skarels if (n->t_flags&T_ACK && (SEQ_GEQ(tp->iss, n->t_ackno) || \ 70*25202Skarels SEQ_GT(n->t_ackno, tp->snd_hi))) \ 71*25202Skarels send_rst(tp, n); \ 72*25202Skarels else if (n->t_flags&T_RST) { \ 73*25202Skarels if (n->t_flags&T_ACK) { \ 74*25202Skarels t_close(tp, ECONNREFUSED); \ 75*25202Skarels retval = CLOSED; \ 76*25202Skarels } \ 77*25202Skarels } else if (n->t_flags&T_SYN) \ 78*25202Skarels retval = SAME; \ 79*25202Skarels break; \ 80*25202Skarels \ 81*25202Skarels case 0: \ 82*25202Skarels /* \ 83*25202Skarels * after bind, but before we've had a chance to \ 84*25202Skarels * listen or connect \ 85*25202Skarels */ \ 86*25202Skarels break; \ 87*25202Skarels \ 88*25202Skarels default: \ 89*25202Skarels { struct sockbuf *sorcv; sequence xend; \ 90*25202Skarels /* \ 91*25202Skarels * Part of packet must fall in window. \ 92*25202Skarels * This allows for segments that are partially retransmits \ 93*25202Skarels * and partially new. \ 94*25202Skarels * otherwise just ACK and drop. \ 95*25202Skarels */ \ 96*25202Skarels sorcv = &inp->inp_socket->so_rcv; \ 97*25202Skarels xend = n->t_seq; \ 98*25202Skarels if (n->t_len) \ 99*25202Skarels /* remember, could be an ACK-only packet */ \ 100*25202Skarels xend += n->t_len -1; \ 101*25202Skarels if (n->t_flags & T_FIN) \ 102*25202Skarels xend ++; /* in case FIN + rxmitted data (TOPS-20) */ \ 103*25202Skarels if (SEQ_LT(xend, tp->rcv_nxt) || \ 104*25202Skarels SEQ_GEQ(n->t_seq, tp->rcv_nxt + sbspace(sorcv))) { \ 105*25202Skarels tp->t_preproc++; \ 106*25202Skarels send_tcp(tp, TCP_CTL); \ 107*25202Skarels HMP_TRAP(T_TCP_WINDOW, (caddr_t)0,0); \ 108*25202Skarels /* \ 109*25202Skarels * Due to 4.2BSD net architecture, don't need to send \ 110*25202Skarels * L_SYN_RCVD socket back to LISTEN on reset since server \ 111*25202Skarels * socket and communication paths are separate. \ 112*25202Skarels */ \ 113*25202Skarels } else if (n->t_flags&T_RST) { \ 114*25202Skarels t_close(tp, ENETRESET); \ 115*25202Skarels retval = CLOSED; \ 116*25202Skarels /* No SYNs allowed unless *SYN_RCVD */ \ 117*25202Skarels } else if ((n->t_flags&T_SYN) && (tp->t_state >= ESTAB)) { \ 118*25202Skarels send_rst(tp, n); \ 119*25202Skarels t_close(tp, ENETRESET); \ 120*25202Skarels retval = CLOSED; \ 121*25202Skarels /* \ 122*25202Skarels * Must have good ACK. Bad ACKs cause resets only in \ 123*25202Skarels * SYN_RCVD states. In other states, this may be a slow pkt? \ 124*25202Skarels */ \ 125*25202Skarels } else if (n->t_flags&T_ACK) \ 126*25202Skarels if (SEQ_GT(tp->snd_una, n->t_ackno) || \ 127*25202Skarels SEQ_GT(n->t_ackno, tp->snd_hi)) { \ 128*25202Skarels if (tp->t_state == SYN_RCVD || \ 129*25202Skarels tp->t_state == L_SYN_RCVD) \ 130*25202Skarels send_rst(tp, n); \ 131*25202Skarels } else { \ 132*25202Skarels /* \ 133*25202Skarels * Acceptable segment: \ 134*25202Skarels * Reset no activity timer on established and \ 135*25202Skarels * closing connections. \ 136*25202Skarels */ \ 137*25202Skarels if (tp->t_state >= ESTAB) \ 138*25202Skarels tp->t_timers[TNOACT] = tp->t_noact; \ 139*25202Skarels retval = SAME; \ 140*25202Skarels } } } } 141*25202Skarels 142*25202Skarels 143*25202Skarels int tcp_net_keep; 144*25202Skarels 145*25202Skarels /* 146*25202Skarels * This is the scheduler for the tcp machine. It is called 147*25202Skarels * from the lower network levels, either directly from the 148*25202Skarels * internet level, in case of input from the network; or 149*25202Skarels * indirectly from netmain, in case of user or timer events 150*25202Skarels * which awaken the main loop. 151*25202Skarels */ 152*25202Skarels tcp_input(mp, fragsize) 153*25202Skarels register struct mbuf *mp; 154*25202Skarels int fragsize; 155*25202Skarels { 156*25202Skarels register struct th *tp; 157*25202Skarels register int hlen; 158*25202Skarels register struct tcpcb *t; 159*25202Skarels register struct inpcb *inp; 160*25202Skarels struct mbuf *m; 161*25202Skarels int i, tlen; 162*25202Skarels struct work w; 163*25202Skarels u_short cks; 164*25202Skarels 165*25202Skarels tcpstat.t_total ++; 166*25202Skarels 167*25202Skarels /* 168*25202Skarels * see ip_input() 169*25202Skarels */ 170*25202Skarels if ((mp->m_off > MMAXOFF) || (mp->m_len < sizeof(struct th))) 171*25202Skarels { 172*25202Skarels if ((mp = m_pullup(mp, sizeof(struct th))) == NULL) 173*25202Skarels { 174*25202Skarels tcpstat.t_tooshort ++; 175*25202Skarels return; 176*25202Skarels } 177*25202Skarels } 178*25202Skarels 179*25202Skarels /* set up needed info from ip header, note that beginning 180*25202Skarels of tcp header struct overlaps ip header. ip options 181*25202Skarels have been removed by ip level option processing */ 182*25202Skarels 183*25202Skarels tp = mtod(mp, struct th *); 184*25202Skarels 185*25202Skarels /* make sure header does not overflow mbuf */ 186*25202Skarels 187*25202Skarels hlen = tp->t_off << TCP_OFFSHIFT; 188*25202Skarels if (hlen < TCPSIZE) 189*25202Skarels { 190*25202Skarels ip_log ((struct ip *) tp, "tcp t_off too small"); 191*25202Skarels netlog(mp); 192*25202Skarels return; 193*25202Skarels } 194*25202Skarels if (hlen > mp->m_len) 195*25202Skarels { 196*25202Skarels if ((mp = m_pullup(mp, hlen)) == NULL) 197*25202Skarels { 198*25202Skarels ip_log((struct ip *) tp, "tcp header overflow"); 199*25202Skarels #ifdef HMPTRAPS 200*25202Skarels /* hmp_trap(T_TCP_OVFLO, (caddr_t)0, 0); */ 201*25202Skarels #else 202*25202Skarels /* netlog(mp); */ 203*25202Skarels #endif 204*25202Skarels return; 205*25202Skarels } 206*25202Skarels tp = mtod(mp, struct th *); 207*25202Skarels } 208*25202Skarels 209*25202Skarels tlen = ((struct ip *)tp)->ip_len; 210*25202Skarels tp->t_len = htons((u_short)tlen); 211*25202Skarels tp->t_next = NULL; 212*25202Skarels tp->t_prev = NULL; 213*25202Skarels tp->t_x1 = 0; 214*25202Skarels 215*25202Skarels /* 216*25202Skarels * do checksum calculation, drop seg if bad 217*25202Skarels */ 218*25202Skarels i = (u_short)tp->t_sum; 219*25202Skarels tp->t_sum = 0; 220*25202Skarels if (i != (cks = (u_short)in_cksum(mp, tlen + sizeof(struct ip)))) 221*25202Skarels { 222*25202Skarels tcpstat.t_badsum++; 223*25202Skarels if (! nosum) 224*25202Skarels { 225*25202Skarels #ifdef HMPTRAPS 226*25202Skarels /* hmp_trap(T_TCP_CKSUM, (caddr_t)0,0); */ 227*25202Skarels #endif 228*25202Skarels inet_cksum_err ("tcp", (struct ip *) tp, (u_long) i, (u_long) cks); 229*25202Skarels netlog(mp); 230*25202Skarels return; 231*25202Skarels } 232*25202Skarels } 233*25202Skarels 234*25202Skarels /* find a tcb for incoming message */ 235*25202Skarels inp = in_pcblookup(&tcp, tp->t_s.s_addr, tp->t_src, 236*25202Skarels tp->t_d.s_addr, tp->t_dst, TRUE); 237*25202Skarels 238*25202Skarels if ((inp != NULL) && ((t = (struct tcpcb *)inp->inp_ppcb) != NULL)) 239*25202Skarels { 240*25202Skarels /* found a tcp for message */ 241*25202Skarels /* byte swap header */ 242*25202Skarels 243*25202Skarels if ((int)(tp->t_len = tlen - hlen) < 0) 244*25202Skarels { 245*25202Skarels ip_log((struct ip *) tp, "tcp header length"); 246*25202Skarels #ifdef HMPTRAPS 247*25202Skarels /* hmp_trap(T_TCP_HLEN, (caddr_t)0,0); */ 248*25202Skarels #else 249*25202Skarels netlog(mp); 250*25202Skarels #endif 251*25202Skarels return; 252*25202Skarels } 253*25202Skarels tp->t_seq = ntohl(tp->t_seq); 254*25202Skarels tp->t_ackno = ntohl(tp->t_ackno); 255*25202Skarels tp->t_win = ntohs((u_short)tp->t_win); 256*25202Skarels tp->t_urp = ntohs((u_short)tp->t_urp); 257*25202Skarels 258*25202Skarels /* record the max fragment size */ 259*25202Skarels 260*25202Skarels t->t_maxfrag = MAX(t->t_maxfrag, fragsize); 261*25202Skarels 262*25202Skarels /* do TCP option processing */ 263*25202Skarels 264*25202Skarels if (hlen > TCPSIZE) 265*25202Skarels tcp_opt(t, tp, hlen); 266*25202Skarels 267*25202Skarels /* check seg seq #, do RST processing */ 268*25202Skarels 269*25202Skarels NETPREPR(t, tp, inp, i); 270*25202Skarels if (i != SAME) 271*25202Skarels { 272*25202Skarels /* segment failed preprocessing. Drop it and 273*25202Skarels * possibly enter new state. For now, always 274*25202Skarels * returns SAME/-1/CLOSED 275*25202Skarels */ 276*25202Skarels m_freem(mp); 277*25202Skarels /* 278*25202Skarels if ((i != -1) && (i != CLOSED)) 279*25202Skarels t->t_state = i; 280*25202Skarels */ 281*25202Skarels } 282*25202Skarels else 283*25202Skarels { 284*25202Skarels if (sbspace(&inp->inp_socket->so_rcv) <= 0 && 285*25202Skarels tp->t_len != 0) 286*25202Skarels { 287*25202Skarels /* 288*25202Skarels * The user's receive q is full. Either the 289*25202Skarels * remote TCP is not paying attention to the 290*25202Skarels * window, or this is a persistence packet. 291*25202Skarels * 292*25202Skarels * The first reason was once common with 293*25202Skarels * TOPS-20. Let's conserve network resources 294*25202Skarels * by holding onto the packet in the unack q. 295*25202Skarels * Place it at the end of the list. 296*25202Skarels */ 297*25202Skarels mp->m_act = NULL; 298*25202Skarels if ((m = t->t_rcv_unack) != NULL) 299*25202Skarels { 300*25202Skarels while (m->m_act != NULL) 301*25202Skarels m = m->m_act; 302*25202Skarels m->m_act = mp; 303*25202Skarels } 304*25202Skarels else 305*25202Skarels t->t_rcv_unack = mp; 306*25202Skarels 307*25202Skarels /* 308*25202Skarels * ACK if it was a window probe, just in case 309*25202Skarels * they have a TNOACT timer running. 310*25202Skarels */ 311*25202Skarels send_tcp(t, TCP_CTL); 312*25202Skarels } 313*25202Skarels else 314*25202Skarels { 315*25202Skarels int act, newstate; 316*25202Skarels struct socket *so; 317*25202Skarels 318*25202Skarels /* set up work entry for seg, and call 319*25202Skarels the fsm to process it */ 320*25202Skarels 321*25202Skarels hlen += sizeof(struct ip); 322*25202Skarels mp->m_off += hlen; 323*25202Skarels mp->m_len -= hlen; 324*25202Skarels 325*25202Skarels /** HAND CODED action() CALL **/ 326*25202Skarels 327*25202Skarels w.w_type = INRECV; 328*25202Skarels w.w_tcb = t; 329*25202Skarels w.w_dat = (char *)tp; 330*25202Skarels 331*25202Skarels /* get index of action routine from 332*25202Skarels * transition table 333*25202Skarels */ 334*25202Skarels act = fstab[t->t_state][INRECV]; 335*25202Skarels 336*25202Skarels /* invalid state transition, just 337*25202Skarels * print a message and ignore */ 338*25202Skarels 339*25202Skarels if (act == 0) 340*25202Skarels { 341*25202Skarels log(KERN_RECOV, "tcp bad state: tcb=%x state=%d INRECV\n", t, t->t_state); 342*25202Skarels m_freem(mp); 343*25202Skarels return; 344*25202Skarels } 345*25202Skarels 346*25202Skarels so = t->t_in_pcb->inp_socket; 347*25202Skarels tcp_net_keep = FALSE; 348*25202Skarels newstate = (*fsactab[act])(&w); 349*25202Skarels 350*25202Skarels /* debugging info */ 351*25202Skarels TCP_DEBUG (so, t, &w, act, newstate); 352*25202Skarels 353*25202Skarels /* if CLOSED, lost tcpcb */ 354*25202Skarels if ((newstate != SAME) && (newstate != CLOSED)) 355*25202Skarels t->t_state = newstate; 356*25202Skarels if (! tcp_net_keep) 357*25202Skarels m_freem(mp); 358*25202Skarels 359*25202Skarels /** END action() **/ 360*25202Skarels } 361*25202Skarels } 362*25202Skarels } 363*25202Skarels else 364*25202Skarels /* nobody wants it */ 365*25202Skarels send_uncon_rst (tp, mp, tlen, hlen); 366*25202Skarels } 367*25202Skarels 368*25202Skarels send_uncon_rst (n, mp, tlen, hlen) 369*25202Skarels register struct th *n; 370*25202Skarels register struct mbuf *mp; 371*25202Skarels { 372*25202Skarels struct in_addr tempinaddr; 373*25202Skarels u_short tempport; 374*25202Skarels int error; 375*25202Skarels 376*25202Skarels /* make sure we don't send a RST in response to an RST */ 377*25202Skarels 378*25202Skarels if (n->t_flags & T_RST) 379*25202Skarels { 380*25202Skarels m_freem(mp); 381*25202Skarels return; 382*25202Skarels } 383*25202Skarels 384*25202Skarels /* free everything but the header */ 385*25202Skarels 386*25202Skarels m_freem(mp->m_next); 387*25202Skarels mp->m_next = NULL; 388*25202Skarels mp->m_len = sizeof(struct th); 389*25202Skarels 390*25202Skarels /* form a reset from the packet and send */ 391*25202Skarels 392*25202Skarels tempinaddr = n->t_d; 393*25202Skarels n->t_d = n->t_s; 394*25202Skarels n->t_s = tempinaddr; 395*25202Skarels 396*25202Skarels tempport = n->t_src; 397*25202Skarels n->t_src = n->t_dst; 398*25202Skarels n->t_dst = tempport; 399*25202Skarels 400*25202Skarels if (n->t_flags&T_ACK) 401*25202Skarels n->t_seq = n->t_ackno; 402*25202Skarels else 403*25202Skarels { 404*25202Skarels n->t_ackno = htonl((u_long) 405*25202Skarels ntohl((u_long)n->t_seq) 406*25202Skarels + tlen - hlen 407*25202Skarels + (n->t_flags&T_SYN ? 1 : 0)); 408*25202Skarels n->t_seq = 0; 409*25202Skarels } 410*25202Skarels n->t_flags = (n->t_flags&T_ACK) ? T_RST : T_RST+T_ACK; 411*25202Skarels n->t_len = htons((u_short)TCPSIZE); 412*25202Skarels n->t_off = TCPSIZE >> TCP_OFFSHIFT; 413*25202Skarels n->t_sum = in_cksum(mp, sizeof(struct th)); 414*25202Skarels 415*25202Skarels NOPCB_IPSEND (mp, TCPSIZE, FALSE, error); 416*25202Skarels tcpstat.t_badsegs++; 417*25202Skarels 418*25202Skarels #ifdef lint 419*25202Skarels error = error; 420*25202Skarels #endif 421*25202Skarels } 422*25202Skarels 423*25202Skarels /* 424*25202Skarels * Entry into TCP finite state machine 425*25202Skarels */ 426*25202Skarels action(wp) 427*25202Skarels register struct work *wp; 428*25202Skarels { 429*25202Skarels register act, newstate; 430*25202Skarels register struct tcpcb *tp; 431*25202Skarels register struct socket *so; 432*25202Skarels 433*25202Skarels tp = wp->w_tcb; 434*25202Skarels so = tp->t_in_pcb->inp_socket; 435*25202Skarels 436*25202Skarels ACTION (tp, so, wp, wp->w_type, wp->w_dat, act, newstate); 437*25202Skarels return(newstate); 438*25202Skarels } 439*25202Skarels 440*25202Skarels 441*25202Skarels struct mbuf *tcpdebuf; 442*25202Skarels int tcprint; 443*25202Skarels 444*25202Skarels /* 445*25202Skarels * Write a record in the tcp debugging log 446*25202Skarels */ 447*25202Skarels tcp_debug(tp, wp, newstate) 448*25202Skarels register struct tcpcb *tp; 449*25202Skarels register struct work *wp; 450*25202Skarels register newstate; 451*25202Skarels { 452*25202Skarels register struct t_debug *dp; 453*25202Skarels register struct mbuf *m; 454*25202Skarels 455*25202Skarels #ifdef TCPDEBUG 456*25202Skarels if (tcprint) 457*25202Skarels { 458*25202Skarels /* 459*25202Skarels * Print debugging info directly on the console (use this for 460*25202Skarels * intial testing only). 461*25202Skarels */ 462*25202Skarels printf("TCP(%x) %s X %s", tp, tcpstates[tp->t_state], 463*25202Skarels tcpinputs[wp->w_type]); 464*25202Skarels 465*25202Skarels if (wp->w_type == ISTIMER) 466*25202Skarels printf("(%s)", tcptimers[wp->w_stype]); 467*25202Skarels 468*25202Skarels printf(" --> %s", 469*25202Skarels tcpstates[ (newstate > 0) ? newstate : tp->t_state]); 470*25202Skarels 471*25202Skarels if (newstate < 0) 472*25202Skarels printf(" (FAILED)\n"); 473*25202Skarels else 474*25202Skarels putchar('\n', 0); 475*25202Skarels } 476*25202Skarels #endif 477*25202Skarels 478*25202Skarels /* 479*25202Skarels * Get an mbuf to write the debugging record into. If we don't already 480*25202Skarels * have one, allocate a new one. 481*25202Skarels */ 482*25202Skarels if ((m = tcpdebuf) == NULL) 483*25202Skarels { 484*25202Skarels register struct mbuf *c; 485*25202Skarels 486*25202Skarels if ((tcpdebuf = m = m_get(M_DONTWAIT, MT_DATA)) == NULL) 487*25202Skarels return; 488*25202Skarels /* 489*25202Skarels * If possible, use a cluster so that we need to wake up the 490*25202Skarels * raw listener less often and reduce likelihood he misses 491*25202Skarels * some information. 492*25202Skarels */ 493*25202Skarels MCLGET(c, 1); 494*25202Skarels if (c) 495*25202Skarels { 496*25202Skarels m->m_off = ((int) c) - ((int) m); 497*25202Skarels m->m_act = (struct mbuf *) TCDBLEN; 498*25202Skarels } 499*25202Skarels else 500*25202Skarels m->m_act = (struct mbuf *) TDBLEN; 501*25202Skarels m->m_len = 0; 502*25202Skarels } 503*25202Skarels 504*25202Skarels dp = (struct t_debug *) (mtod(m, char *) + m->m_len); 505*25202Skarels /* 506*25202Skarels * Set up the debugging record. 507*25202Skarels */ 508*25202Skarels dp->t_iptime = iptime(); 509*25202Skarels dp->t_input = wp->w_type; 510*25202Skarels dp->t_timer = wp->w_stype; 511*25202Skarels dp->t_newstate = newstate; 512*25202Skarels if (tp != NULL) 513*25202Skarels { 514*25202Skarels dp->t_oldstate = tp->t_state; 515*25202Skarels dp->t_tcb = (*tp); /* structure copy */ 516*25202Skarels } 517*25202Skarels else 518*25202Skarels dp->t_oldstate = 0; 519*25202Skarels 520*25202Skarels if (wp->w_type == INRECV) 521*25202Skarels { 522*25202Skarels register struct th *n; 523*25202Skarels 524*25202Skarels n = (struct th *)wp->w_dat; 525*25202Skarels dp->t_hdr = (*n); /* structure copy */ 526*25202Skarels } 527*25202Skarels /* 528*25202Skarels * If the mbuf is full, dispatch it to a raw listener. 529*25202Skarels * Also flush if the connection we're debugging closes so that 530*25202Skarels * packet-printer/systems analyst sees final transitions. 531*25202Skarels */ 532*25202Skarels m->m_len += sizeof(struct t_debug); 533*25202Skarels if ((m->m_len >= ((int) m->m_act)) || (newstate == CLOSED)) 534*25202Skarels { 535*25202Skarels m->m_act = 0; 536*25202Skarels tcpdebuglog(m); 537*25202Skarels tcpdebuf = NULL; 538*25202Skarels } 539*25202Skarels } 540