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