xref: /csrg-svn/sys/netiso/tp_emit.c (revision 51204)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)tp_emit.c	7.12 (Berkeley) 09/26/91
8  */
9 
10 /***********************************************************
11 		Copyright IBM Corporation 1987
12 
13                       All Rights Reserved
14 
15 Permission to use, copy, modify, and distribute this software and its
16 documentation for any purpose and without fee is hereby granted,
17 provided that the above copyright notice appear in all copies and that
18 both that copyright notice and this permission notice appear in
19 supporting documentation, and that the name of IBM not be
20 used in advertising or publicity pertaining to distribution of the
21 software without specific, written prior permission.
22 
23 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 SOFTWARE.
30 
31 ******************************************************************/
32 
33 /*
34  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
35  */
36 /*
37  * ARGO TP
38  *
39  * $Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $
40  * $Source: /usr/argo/sys/netiso/RCS/tp_emit.c,v $
41  *
42  * This file contains tp_emit() and tp_error_emit(), which
43  * form TPDUs and hand them to ip.
44  * They take data in the form of mbuf chain, allocate mbufs as
45  * necessary for headers, and set the fields as appropriate from
46  * information found in the tpcb and net-level pcb.
47  *
48  * The worst thing about this code is adding the variable-length
49  * options on a machine that requires alignment for any memory access
50  * that isn't of size 1.  See the macro ADDOPTION() below.
51  *
52  * We don't do any concatenation. (There's a kludge to test the
53  * basic mechanism of separation under the 'w' tpdebug option, that's all.)
54  */
55 
56 #include "param.h"
57 #include "mbuf.h"
58 #include "socket.h"
59 #include "socketvar.h"
60 #include "protosw.h"
61 #include "errno.h"
62 #include "types.h"
63 #include "time.h"
64 #include "iso.h"
65 #include "iso_pcb.h"
66 #include "argo_debug.h"
67 #include "tp_timer.h"
68 #include "tp_param.h"
69 #include "tp_stat.h"
70 #include "tp_pcb.h"
71 #include "tp_tpdu.h"
72 #include "tp_trace.h"
73 #include "tp_meas.h"
74 #include "tp_seq.h"
75 #include "iso_errno.h"
76 
77 #include "../net/if.h"
78 #ifdef TRUE
79 #undef FALSE
80 #undef TRUE
81 #endif
82 #include "../netccitt/x25.h"
83 #include "../netccitt/pk.h"
84 #include "../netccitt/pk_var.h"
85 
86 void iso_gen_csum();
87 
88 
89 /* Here is a mighty kludge.  The token ring misorders packets if you
90  * fire them at it too fast, and TP sans checksum is "too fast", so
91  * we have introduced a delay when checksumming isn't used.
92  */
93 char tp_delay = 0x00; /* delay to keep token ring from blowing it */
94 
95 /*
96  * NAME:	tp_emit()
97  *
98  * CALLED FROM: tp.trans and from tp_sbsend()
99  *
100  * FUNCTION and ARGUMENTS:
101  * 	Emits one tpdu of the type (dutype), of the format appropriate
102  * 	to the connection described by the pcb (tpcb), with sequence
103  * 	number (seq) (where appropriate), end-of-tsdu bit (eot) where
104  * 	appropriate, and with the data in the mbuf chain (data).
105  * 	For DR and ER tpdus, the argument (eot) is
106  * 	the reason for issuing the tpdu rather than an end-of-tsdu indicator.
107  *
108  * RETURNS:
109  * 	0  OK
110  * 	ENOBUFS
111  * 	E* returned from net layer output rtn
112  *
113  * SIDE EFFECTS:
114  *
115  * NOTES:
116  *
117  * 	WE ASSUME that the tp header + all options will fit in ONE mbuf.
118  *	If mbufs are 256 this will most likely be true, but if they are 128 it's
119  *	possible that they won't.
120  *	If you used every option on the CR + max. user data you'd overrun
121  *	112 but unless you used > 115 bytes for the security
122  *	parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
123  *	We don't support the security parameter, so this isn't a problem.
124  *	If security is added, we ought to remove this assumption.
125  *
126  *  We do not implement the flow control confirmation "element of procedure".
127  *  A) it should not affect interoperability,
128  *  B) it should not be necessary - the protocol will eventually
129  *   	straighten things out w/o FCC, as long as we don't have severely
130  *		mismatched keepalive and inactivity timers, and
131  *	C) it appears not to be REQUIRED, and
132  *  D) it's incredibly grotesque, and no doubt will lengthen a few
133  *   	critical paths.
134  *  HOWEVER, we're thinking about putting it in anyway, for
135  *  completeness, just like we did with ack subsequencing.
136  */
137 
138 int
139 tp_emit(dutype,	tpcb, seq, eot, data)
140 	int dutype;
141 	struct tp_pcb *tpcb;
142 	SeqNum	seq;
143 	u_int 	eot;
144 	struct mbuf *data;
145 {
146 	register struct tpdu *hdr;
147 	register struct mbuf *m;
148 	int csum_offset=0;
149 	int datalen = 0;
150 	int error = 0;
151  	SeqNum olduwe;
152 	int acking_ooo;
153 
154 	/* NOTE:
155 	 * here we treat tpdu_li as if it DID include the li field, up until
156 	 * the end, at which time we subtract 1
157 	 * THis is because if we subtract 1 right away, we end up adding
158 	 * one every time we add an option.
159 	 */
160 	IFDEBUG(D_EMIT)
161 		printf(
162 	"tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
163 		dutype, tpcb, eot, seq, data);
164 	ENDDEBUG
165 
166 	if (dutype == CR_TPDU || dutype == CC_TPDU) {
167 		m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
168 		if (m) {
169 			m->m_type = TPMT_TPHDR;
170 			mbstat.m_mtypes[TPMT_TPHDR]++;
171 			m->m_next = MNULL;
172 			m->m_nextpkt = MNULL;
173 			m->m_data = m->m_pktdat;
174 			m->m_flags = M_PKTHDR;
175 		}
176 	} else {
177 		MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
178 	}
179 	m->m_data += max_hdr;
180 	if (m == NULL) {
181 		if(data != (struct mbuf *)0)
182 			m_freem(data);
183 		error = ENOBUFS;
184 		goto done;
185 	}
186 	m->m_len = sizeof(struct tpdu);
187 	m->m_act = MNULL;
188 
189 	hdr = mtod(m, struct tpdu *);
190 	bzero((caddr_t)hdr, sizeof(struct tpdu));
191 
192 	{
193 		int 	tp_headersize();
194 
195 		hdr->tpdu_type = dutype;
196 		hdr->tpdu_li = tp_headersize(dutype, tpcb);
197 		/*
198 		 * class 0 doesn't use this for DT
199 		 * it'll just get overwritten below
200 		 */
201 		hdr->tpdu_dref = htons(tpcb->tp_fref);
202 		if( tpcb->tp_use_checksum ||
203 			(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
204 			csum_offset =  hdr->tpdu_li + 2; /* DOESN'T include csum */
205 			ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */);
206 			IFDEBUG(D_CHKSUM)
207 				printf(
208 					"tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
209 						csum_offset, hdr->tpdu_li);
210 			ENDDEBUG
211 		}
212 		/*
213 		 * VARIABLE PARTS...
214 		 */
215 		switch( dutype ) {
216 
217 		case CR_TPDU_type:
218 			hdr->tpdu_CRdref_0 = 0;	/* must be zero */
219 			if (!tpcb->tp_cebit_off) {
220 				tpcb->tp_win_recv = tp_start_win << 8;
221 				LOCAL_CREDIT(tpcb);
222 				CONG_INIT_SAMPLE(tpcb);
223 			} else
224 				LOCAL_CREDIT(tpcb);
225 
226 
227 		case CC_TPDU_type:
228 				{
229 					u_char x;
230 
231 				hdr->tpdu_CCsref =  htons(tpcb->tp_lref); /* same as CRsref */
232 
233 				if( tpcb->tp_class > TP_CLASS_1 ) {
234 /* ifdef CE_BIT, we did this in tp_input when the CR came in */
235 					if (tpcb->tp_cebit_off)
236 						LOCAL_CREDIT( tpcb );
237 					tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
238 					tpcb->tp_sent_rcvnxt = 1;
239 					tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
240 					hdr->tpdu_cdt = tpcb->tp_lcredit;
241 				} else {
242 #ifdef TPCONS
243 					if (tpcb->tp_netservice == ISO_CONS) {
244 						struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
245 						struct pklcd *lcp = (struct pklcd *)(isop->isop_chan);
246 						lcp->lcd_flags &= ~X25_DG_CIRCUIT;
247 					}
248 #endif
249 					hdr->tpdu_cdt = 0;
250 				}
251 				hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
252 				hdr->tpdu_CCoptions =
253 					(tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
254 					(tpcb->tp_use_efc? TPO_USE_EFC:0);
255 
256 				IFPERF(tpcb)
257 					u_char perf_meas = tpcb->tp_perf_on;
258 					ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
259 				ENDPERF
260 
261 				if( dutype == CR_TPDU_type ) {
262 					IncStat(ts_CR_sent);
263 
264 					ASSERT( tpcb->tp_lsuffixlen > 0 );
265 					ASSERT( tpcb->tp_fsuffixlen > 0 );
266 
267 					ADDOPTION(TPP_calling_sufx, hdr,
268 						tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
269 					ADDOPTION(TPP_called_sufx, hdr,
270 						tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
271 				} else {
272 					IncStat(ts_CC_sent);
273 				}
274 
275 				ADDOPTION(TPP_tpdu_size, hdr,
276 					sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
277 
278 				if (tpcb->tp_class != TP_CLASS_0) {
279 					short millisec = 500*(tpcb->tp_sendack_ticks);
280 
281 					millisec = htons(millisec);
282 					ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
283 
284 					x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
285 					 |	(tpcb->tp_use_rcc?  TPAO_USE_RCC : 0)
286 					 |  (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
287 					 |	(tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
288 					ADDOPTION(TPP_addl_opt, hdr, 1, x);
289 
290 				}
291 
292 				if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
293 
294 					ASSERT( 1 == sizeof(tpcb->tp_vers) );
295 					ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
296 
297 					/* for each alt protocol class x,
298 					 * 	x = x<<4;
299 					 *  option = concat(option, x);
300 					 * Well, for now we only have TP0 for an
301 					 * alternative so... this is easy.
302 					 *
303 					 * HOWEVER... There should be NO alt protocol
304 					 * class over CLNS.  Need to see if the route suggests
305 					 * CONS, and iff so add alt class.
306 					 */
307 					x = 0;
308 					ADDOPTION(TPP_alt_class, hdr, 1, x);
309 				}
310 
311 				if( hdr->tpdu_li > MLEN)
312 					panic("tp_emit CR/CC");
313 			}
314 			break;
315 
316 		case DR_TPDU_type:
317 			if( hdr->tpdu_DRdref == 0 ) {
318 				/* don't issue the DR */
319 				goto done;
320 			}
321 			hdr->tpdu_cdt = 0;
322 			hdr->tpdu_DRsref = htons(tpcb->tp_lref);
323 			hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
324 
325 			/* forget the add'l information variable part */
326 			IncStat(ts_DR_sent);
327 			break;
328 
329 		case DC_TPDU_type: /* not used in class 0 */
330 			ASSERT( tpcb->tp_class != TP_CLASS_0);
331 			hdr->tpdu_DCsref =  htons(tpcb->tp_lref);
332 			hdr->tpdu_cdt = 0;
333 			data = (struct mbuf *)0;
334 			IncStat(ts_DC_sent);
335 			break;
336 
337 		case XAK_TPDU_type: /* xak not used in class 0 */
338 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
339 			hdr->tpdu_cdt = 0;
340 
341 			IFTRACE(D_XPD)
342 				tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
343 			ENDTRACE
344 			data = (struct mbuf *)0;
345 			if (tpcb->tp_xtd_format) {
346 #ifdef BYTE_ORDER
347 				union seq_type seqeotX;
348 
349 				seqeotX.s_seq = seq;
350 				seqeotX.s_eot = 1;
351 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
352 #else
353 				hdr->tpdu_XAKseqX = seq;
354 #endif BYTE_ORDER
355 			} else {
356 				hdr->tpdu_XAKseq = seq;
357 			}
358 			IncStat(ts_XAK_sent);
359 			IncPStat(tpcb, tps_XAK_sent);
360 			break;
361 
362 		case XPD_TPDU_type: /* xpd not used in class 0 */
363 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
364 			hdr->tpdu_cdt = 0;
365 			if (tpcb->tp_xtd_format) {
366 #ifdef BYTE_ORDER
367 				union seq_type seqeotX;
368 
369 				seqeotX.s_seq = seq;
370 				seqeotX.s_eot = 1;
371 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
372 #else
373 				hdr->tpdu_XPDseqX = seq;
374 				hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
375 #endif BYTE_ORDER
376 			} else {
377 				hdr->tpdu_XPDseq = seq;
378 				hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
379 			}
380 			IncStat(ts_XPD_sent);
381 			IncPStat(tpcb, tps_XPD_sent);
382 
383 			/* kludge to test the input size checking */
384 			IFDEBUG(D_SIZE_CHECK)
385 				/*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
386 					printf("Sending too much data on XPD: 18 bytes\n");
387 					data->m_len = 18;
388 				}*/
389 			ENDDEBUG
390 			break;
391 
392 		case DT_TPDU_type:
393 			hdr->tpdu_cdt = 0;
394 			IFTRACE(D_DATA)
395 				tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
396 					hdr->tpdu_li, 0);
397 			ENDTRACE
398 			if (tpcb->tp_xtd_format) {
399 #ifdef BYTE_ORDER
400 				union seq_type seqeotX;
401 
402 				seqeotX.s_seq = seq;
403 				seqeotX.s_eot = eot;
404 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
405 #else
406 				hdr->tpdu_DTseqX = seq;
407 				hdr->tpdu_DTeotX = eot;
408 #endif BYTE_ORDER
409 			} else if (tpcb->tp_class == TP_CLASS_0) {
410 				IFDEBUG(D_EMIT)
411 					printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
412 					dump_buf( hdr, hdr->tpdu_li + 1 );
413 				ENDDEBUG
414 				((struct tp0du *)hdr)->tp0du_eot = eot;
415 				((struct tp0du *)hdr)->tp0du_mbz = 0;
416 				IFDEBUG(D_EMIT)
417 					printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
418 					dump_buf( hdr, hdr->tpdu_li + 1 );
419 				ENDDEBUG
420 			} else {
421 				hdr->tpdu_DTseq = seq;
422 				hdr->tpdu_DTeot = eot;
423 			}
424 			if(eot) {
425 				IncStat(ts_EOT_sent);
426 			}
427 			IncStat(ts_DT_sent);
428 			IncPStat(tpcb, tps_DT_sent);
429 			break;
430 
431 		case AK_TPDU_type:/* ak not used in class 0 */
432 			ASSERT( tpcb->tp_class != TP_CLASS_0);
433 			data = (struct mbuf *)0;
434 			olduwe = tpcb->tp_sent_uwe;
435 
436 			if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
437 				LOCAL_CREDIT( tpcb );
438 				tpcb->tp_sent_uwe =
439 					SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
440 				tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
441 				acking_ooo = 0;
442 			} else
443 				acking_ooo = 1;
444 
445 			IFDEBUG(D_RENEG)
446 				/* occasionally fake a reneging so
447 					you can test subsequencing */
448 				if( olduwe & 0x1 ) {
449 					tpcb->tp_reneged = 1;
450 					IncStat(ts_ldebug);
451 				}
452 			ENDDEBUG
453 			/* Are we about to reneg on credit?
454 			 * When might we do so?
455 			 *	a) when using optimistic credit (which we no longer do).
456 			 *  b) when drain() gets implemented (not in the plans).
457 			 *  c) when D_RENEG is on.
458 			 *  d) when DEC BIT response is implemented.
459 			 *	(not- when we do this, we'll need to implement flow control
460 			 *	confirmation)
461 			 */
462 			if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
463 				tpcb->tp_reneged = 1;
464 				IncStat(ts_lcdt_reduced);
465 				IFTRACE(D_CREDIT)
466 					tptraceTPCB(TPPTmisc,
467 						"RENEG: olduwe newuwe lcredit rcvnxt",
468 						olduwe,
469 						tpcb->tp_sent_uwe, tpcb->tp_lcredit,
470 						tpcb->tp_rcvnxt);
471 				ENDTRACE
472 			}
473 			IFPERF(tpcb)
474 				/* new lwe is less than old uwe means we're
475 				 * acking before we received a whole window full
476 				 */
477 				if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
478 					/* tmp1 = number of pkts fewer than the full window */
479 					register int tmp1 =
480 						(int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
481 
482 					if(tmp1 > TP_PM_MAX)
483 						tmp1 = TP_PM_MAX;
484 					IncPStat( tpcb,  tps_ack_early[tmp1] );
485 
486 					/* tmp1 = amt of new cdt we're advertising */
487 					tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
488 					if(tmp1 > TP_PM_MAX )
489 						tmp1 = TP_PM_MAX;
490 
491 					IncPStat( tpcb,
492 							tps_cdt_acked [ tmp1 ]
493 							[ ((tpcb->tp_lcredit > TP_PM_MAX)?
494 								TP_PM_MAX:tpcb->tp_lcredit) ] );
495 
496 				}
497 			ENDPERF
498 
499 			IFTRACE(D_ACKSEND)
500 				tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
501 					tpcb->tp_r_subseq, 0);
502 			ENDTRACE
503 			if (tpcb->tp_xtd_format) {
504 #ifdef BYTE_ORDER
505 				union seq_type seqeotX;
506 
507 				seqeotX.s_seq = seq;
508 				seqeotX.s_eot = 0;
509 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
510 				hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
511 #else
512 				hdr->tpdu_cdt = 0;
513 				hdr->tpdu_AKseqX = seq;
514 				hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
515 #endif BYTE_ORDER
516 			} else {
517 				hdr->tpdu_AKseq = seq;
518 				hdr->tpdu_AKcdt = tpcb->tp_lcredit;
519 			}
520 			if ((tpcb->tp_class == TP_CLASS_4) &&
521 				(tpcb->tp_reneged || acking_ooo)) {
522 				/*
523 				 * Ack subsequence parameter req'd if WE reneged on
524 				 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
525 				 */
526 				IFDEBUG(D_RENEG)
527 					printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
528 				ENDDEBUG
529 				tpcb->tp_s_subseq++;
530 				/*
531 				 * add tmp subseq and do a htons on it.
532 				 */
533 				ADDOPTION(TPP_subseq, hdr,
534 					sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
535 			} else
536 				tpcb->tp_s_subseq = 0;
537 
538 			if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
539 				/*
540 				 * Rules for sending FCC ("should" send when) :
541 				 * %a) received an ack from peer with NO NEWS whatsoever,
542 				 *  	and it did not contain an FCC
543 				 * 	b) received an ack from peer that opens its closed window.
544 				 * 	c) received an ack from peer after it reneged on its
545 				 *		offered credit, AND this ack raises UWE but LWE is same
546 				 *		and below UWE at time of reneging (reduction)
547 				 * Now, ISO 8073 12.2.3.8.3 says
548 				 * that a retransmitted AK shall not contain the FCC
549 				 * parameter.  Now, how the hell you tell the difference
550 				 * between a retransmitted ack and an ack that's sent in
551 				 * response to a received ack, I don't know, because without
552 				 * any local activity, and w/o any received DTs, they
553 				 * will contain exactly the same credit/seq# information.
554 				 * Anyway, given that the "retransmission of acks"
555 				 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
556 				 * don't do it (although the peer can't tell that), we
557 				 * ignore this last rule.
558 				 *
559 				 * We send FCC for reasons a) and b) only.
560 				 * To add reason c) would require a ridiculous amount of state.
561 				 *
562 				 */
563 				u_short 	bogus[4]; /* lwe(32), subseq(16), cdt(16) */
564 				SeqNum		lwe;
565 				u_short		subseq, fcredit;
566 
567 				tpcb->tp_sendfcc = 0;
568 
569 				lwe = (SeqNum) htonl(tpcb->tp_snduna);
570 				subseq = htons(tpcb->tp_r_subseq);
571 				fcredit = htons(tpcb->tp_fcredit);
572 
573 				bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
574 				bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
575 				bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
576 
577 				IFTRACE(D_ACKSEND)
578 					tptraceTPCB(TPPTmisc,
579 						"emit w/FCC: snduna r_subseq fcredit",
580 						tpcb->tp_snduna, tpcb->tp_r_subseq,
581 						tpcb->tp_fcredit, 0);
582 				ENDTRACE
583 
584 				IFDEBUG(D_ACKSEND)
585 					printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
586 						TPP_flow_cntl_conf,
587 						hdr, sizeof(bogus), bogus[0]);
588 				ENDDEBUG
589 				ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
590 				IFDEBUG(D_ACKSEND)
591 					printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
592 						hdr, hdr->tpdu_li);
593 					printf(
594 					"after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
595 							csum_offset, hdr->tpdu_li);
596 				ENDDEBUG
597 
598 			}
599 			tpcb->tp_reneged = 0;
600 			tpcb->tp_sent_rcvnxt = seq;
601 			if (tpcb->tp_fcredit == 0) {
602 				int timo = tpcb->tp_keepalive_ticks;
603 				if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
604 					tpcb->tp_rxtshift++;
605 				timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
606 				tp_ctimeout(tpcb, TM_sendack, timo);
607 			} else
608 				tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
609 			IncStat(ts_AK_sent);
610 			IncPStat(tpcb, tps_AK_sent);
611 			IFDEBUG(D_ACKSEND)
612 				printf(
613 				"2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
614 						csum_offset, hdr->tpdu_li);
615 			ENDDEBUG
616 			break;
617 
618 		case ER_TPDU_type:
619 			hdr->tpdu_ERreason = eot;
620 			hdr->tpdu_cdt = 0;
621 			/* no user data */
622 			data = (struct mbuf *)0;
623 			IncStat(ts_ER_sent);
624 			break;
625 		}
626 
627 	}
628 	ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
629 
630 	m->m_next = data;
631 
632 	ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
633 	ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
634 
635 	m->m_len = hdr->tpdu_li ;
636 	hdr->tpdu_li --; /* doesn't include the li field */
637 
638 	datalen = m_datalen( m ); /* total len */
639 
640 	ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
641 				when CLNP is used; leave in here for the time being */
642 		IFDEBUG(D_ACKSEND)
643 			printf(
644 			"4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
645 					csum_offset, hdr->tpdu_li);
646 		ENDDEBUG
647 	if( datalen > tpcb->tp_l_tpdusize ) {
648 		printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
649 			datalen, tpcb->tp_l_tpdusize);
650 	}
651 	IFDEBUG(D_EMIT)
652 		printf(
653 		"tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
654 		m->m_len, csum_offset, datalen);
655 	ENDDEBUG
656 	if( tpcb->tp_use_checksum ||
657 		(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
658 		iso_gen_csum(m, csum_offset, datalen);
659 	}
660 
661 	IFDEBUG(D_EMIT)
662 	printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
663 		tpcb, dutype, datalen);
664 		dump_buf(mtod(m, caddr_t), datalen);
665 	ENDDEBUG
666 
667 	IFPERF(tpcb)
668 		if( dutype == DT_TPDU_type ) {
669 			PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
670 			tpmeas( tpcb->tp_lref, TPtime_to_ll,  (struct timeval *)0,
671 				seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
672 		}
673 	ENDPERF
674 
675 	IFTRACE(D_EMIT)
676 		tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
677 	ENDTRACE
678 	IFDEBUG(D_EMIT)
679 		printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
680 			tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
681 	ENDDEBUG
682 
683 	{ extern char tp_delay;
684 
685 		if( tp_delay )
686 			if( tpcb->tp_use_checksum == 0 ) {
687 				register u_int i  = tp_delay;
688 				for (; i!= 0; i--)
689 					(void) iso_check_csum(m, datalen);
690 			}
691 	}
692 	ASSERT( m->m_len > 0 );
693 	error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
694 		!tpcb->tp_use_checksum);
695 	IFDEBUG(D_EMIT)
696 		printf("OUTPUT: returned 0x%x\n", error);
697 	ENDDEBUG
698 	IFTRACE(D_EMIT)
699 		tptraceTPCB(TPPTmisc,
700 			"tp_emit nlproto->output netservice returns datalen",
701 			tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
702 	ENDTRACE
703 done:
704 	if (error) {
705 		if (dutype == AK_TPDU_type)
706 			tp_ctimeout(tpcb, TM_sendack, 1);
707 		if (error == E_CO_QFULL) {
708 			tp_quench(tpcb, PRC_QUENCH);
709 			return 0;
710 		}
711 	}
712 	return error;
713 }
714 /*
715  * NAME:		tp_error_emit()
716  * CALLED FROM:	tp_input() when a DR or ER is to be issued in
717  * 		response to an input error.
718  * FUNCTION and ARGUMENTS:
719  * 		The error type is the first argument.
720  * 		The argument (sref) is the source reference on the bad incoming tpdu,
721  * 		and is used for a destination reference on the outgoing packet.
722  * 		(faddr) and (laddr) are the foreign and local addresses for this
723  *		connection.
724  * 		(erdata) is a ptr to the errant incoming tpdu, and is copied into the
725  * 		outgoing ER, if an ER is to be issued.
726  * 		(erlen)  is the number of octets of the errant tpdu that we should
727  * 		try to copy.
728  * 		(tpcb) is the pcb that describes the connection for which the bad tpdu
729  * 		arrived.
730  * RETURN VALUES:
731  * 		0 OK
732  *  	ENOBUFS
733  *  	E* from net layer datagram output routine
734  * SIDE EFFECTS:
735  *
736  * NOTES:
737  */
738 
739 int
740 tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
741 	dgout_routine)
742 	int				error;
743 	u_long			sref;
744 	struct sockaddr_iso *faddr, *laddr;
745 	struct mbuf 	*erdata;
746 	int 			erlen;
747 	struct tp_pcb 	*tpcb;
748 	caddr_t			cons_channel;
749 	int				(*dgout_routine)();
750 {
751 	int						dutype;
752 	int 					datalen = 0;
753 	register struct tpdu	*hdr;
754 	register struct mbuf	*m;
755 	int						csum_offset;
756 
757 	IFTRACE(D_ERROR_EMIT)
758 		tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
759 			error, sref, tpcb, erlen);
760 	ENDTRACE
761 	IFDEBUG(D_ERROR_EMIT)
762 		printf(
763 		"tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
764 			error, sref, tpcb, erlen, cons_channel);
765 	ENDDEBUG
766 
767 	MGET(m, M_DONTWAIT, TPMT_TPHDR);
768 	if (m == NULL) {
769 		return ENOBUFS;
770 	}
771 	m->m_len = sizeof(struct tpdu);
772 	m->m_act = MNULL;
773 
774 	hdr = mtod(m, struct tpdu *);
775 
776 	IFDEBUG(D_ERROR_EMIT)
777 		printf("[error 0x%x] [error&0xff  0x%x] [(char)error 0x%x]\n",
778 			error, error&0xff, (char)error);
779 	ENDDEBUG
780 
781 
782 	if (error & TP_ERROR_SNDC)
783 		dutype = DC_TPDU_type;
784 	else if (error & 0x40) {
785 		error &= ~0x40;
786 		dutype = ER_TPDU_type;
787 	} else
788 		dutype = DR_TPDU_type;
789 	error &= 0xff;
790 
791 	hdr->tpdu_type = dutype;
792 	hdr->tpdu_cdt = 0;
793 
794 	switch( dutype ) {
795 
796 	case DC_TPDU_type:
797 		IncStat(ts_DC_sent);
798 		hdr->tpdu_li = 6;
799 		hdr->tpdu_DCdref = htons(sref);
800 		hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
801 		IFDEBUG(D_ERROR_EMIT)
802 			printf("DC case:\n");
803 			dump_buf( hdr, 6);
804 		ENDDEBUG
805 		/* forget the add'l information variable part */
806 		break;
807 
808 	case DR_TPDU_type:
809 		IncStat(ts_DR_sent);
810 		hdr->tpdu_li = 7;
811 		hdr->tpdu_DRdref = htons(sref);
812 		hdr->tpdu_DRsref = 0;
813 		hdr->tpdu_DRreason = (char)error;
814 		IFDEBUG(D_ERROR_EMIT)
815 			printf("DR case:\n");
816 			dump_buf( hdr, 7);
817 		ENDDEBUG
818 		/* forget the add'l information variable part */
819 		break;
820 
821 	case ER_TPDU_type:
822 		IncStat(ts_ER_sent);
823 		hdr->tpdu_li = 5;
824 		hdr->tpdu_ERreason = (char)error;
825 		hdr->tpdu_ERdref = htons(sref);
826 		break;
827 
828 	default:
829 		ASSERT(0);
830 		printf("TP PANIC: bad dutype 0x%x\n", dutype);
831 	}
832 
833 	if(tpcb)
834 		if( tpcb->tp_use_checksum ) {
835 			ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
836 			csum_offset =  hdr->tpdu_li - 2;
837 		}
838 
839 	ASSERT( hdr->tpdu_li < MLEN );
840 
841 	if (dutype == ER_TPDU_type) {
842 		/* copy the errant tpdu into another 'variable part' */
843 		register caddr_t P;
844 
845 		IFTRACE(D_ERROR_EMIT)
846 			tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
847 				0,0);
848 		ENDTRACE
849 		IFDEBUG(D_ERROR_EMIT)
850 			printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
851 		ENDDEBUG
852 
853 		/* copy at most as many octets for which you have room */
854 		if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
855 			erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
856 
857 		/* add the "invalid tpdu" parameter : required in class 0 */
858 		P = (caddr_t)hdr + (int)(hdr->tpdu_li);
859 		vbptr(P)->tpv_code =  TPP_invalid_tpdu; /* parameter code */
860 		vbptr(P)->tpv_len = erlen;	/* parameter length */
861 		m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
862 
863 		/* tp_input very likely handed us an mbuf chain w/ nothing in
864 		 * the first mbuf and the data following the empty mbuf
865 		 */
866 		if(erdata->m_len == 0) {
867 			erdata = m_free(erdata); /* returns the next mbuf on the chain */
868 		}
869 		/*
870 		 * copy only up to the bad octet
871 		 * (or max that will fit in a header
872 		 */
873 		m->m_next = m_copy(erdata, 0, erlen);
874 		hdr->tpdu_li += erlen + 2;
875 		m_freem(erdata);
876 	} else {
877 		IFDEBUG(D_ERROR_EMIT)
878 			printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
879 			dump_buf( (char *)hdr, hdr->tpdu_li );
880 		ENDDEBUG
881 		m->m_len = hdr->tpdu_li ;
882 		m_freem(erdata);
883 	}
884 
885 	hdr->tpdu_li --;
886 	IFTRACE(D_ERROR_EMIT)
887 		tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
888 	ENDTRACE
889 
890 	datalen = m_datalen( m);
891 	if (tpcb) {
892 		if( tpcb->tp_use_checksum ) {
893 			IFTRACE(D_ERROR_EMIT)
894 				tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
895 			ENDTRACE
896 			IFDEBUG(D_ERROR_EMIT)
897 				printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
898 					datalen, csum_offset);
899 			ENDDEBUG
900 
901 			iso_gen_csum(m, csum_offset, datalen);
902 		}
903 
904 		IFDEBUG(D_ERROR_EMIT)
905 			printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
906 				tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
907 		ENDDEBUG
908 	}
909 	if (cons_channel) {
910 #ifdef TPCONS
911 		struct pklcd *lcp = (struct pklcd *)cons_channel;
912 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
913 
914 		tpcons_dg_output(cons_channel, m, datalen);
915 		/* was if (tpcb == 0) iso_pcbdetach(isop); */
916 		/* but other side may want to try again over same VC,
917 		   so, we'll depend on him closing it, but in case it gets forgotten
918 		   we'll mark it for garbage collection */
919 		lcp->lcd_flags |= X25_DG_CIRCUIT;
920 		IFDEBUG(D_ERROR_EMIT)
921 			printf("OUTPUT: dutype 0x%x channel 0x%x\n",
922 				dutype, cons_channel);
923 		ENDDEBUG
924 #else
925 		printf("TP panic! cons channel 0x%x but not cons configured\n",
926 			cons_channel);
927 #endif
928 	} else if (tpcb) {
929 
930 		IFDEBUG(D_ERROR_EMIT)
931 			printf("tp_error_emit 1 sending DG: Laddr\n");
932 			dump_addr((struct sockaddr *)laddr);
933 			printf("Faddr\n");
934 			dump_addr((struct sockaddr *)faddr);
935 		ENDDEBUG
936 		return (tpcb->tp_nlproto->nlp_dgoutput)(
937 			&laddr->siso_addr,
938 			&faddr->siso_addr,
939 			m, datalen,
940 					/* no route */	(caddr_t)0, !tpcb->tp_use_checksum);
941 	} else if (dgout_routine) {
942 			IFDEBUG(D_ERROR_EMIT)
943 				printf("tp_error_emit sending DG: Laddr\n");
944 				dump_addr((struct sockaddr *)laddr);
945 				printf("Faddr\n");
946 				dump_addr((struct sockaddr *)faddr);
947 			ENDDEBUG
948 				return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
949 					m, datalen, /* no route */
950 					(caddr_t)0, /* nochecksum==false */0);
951 	} else {
952 			IFDEBUG(D_ERROR_EMIT)
953 				printf("tp_error_emit DROPPING \n", m);
954 			ENDDEBUG
955 			IncStat(ts_send_drop);
956 			m_freem(m);
957 			return 0;
958 	}
959 }
960