xref: /original-bsd/sys/netiso/tp_emit.c (revision 3b6250d9)
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.14 (Berkeley) 05/27/92
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 		case CC_TPDU_type:
220 			if (!tpcb->tp_cebit_off) {
221 				tpcb->tp_win_recv = tp_start_win << 8;
222 				LOCAL_CREDIT(tpcb);
223 				CONG_INIT_SAMPLE(tpcb);
224 			} else
225 				LOCAL_CREDIT(tpcb);
226 
227 /* Case CC_TPDU_type used to be here */
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 					tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
235 					tpcb->tp_sent_rcvnxt = 1;
236 					tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
237 					hdr->tpdu_cdt = tpcb->tp_lcredit;
238 				} else {
239 #ifdef TPCONS
240 					if (tpcb->tp_netservice == ISO_CONS) {
241 						struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
242 						struct pklcd *lcp = (struct pklcd *)(isop->isop_chan);
243 						lcp->lcd_flags &= ~X25_DG_CIRCUIT;
244 					}
245 #endif
246 					hdr->tpdu_cdt = 0;
247 				}
248 				hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
249 				hdr->tpdu_CCoptions =
250 					(tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
251 					(tpcb->tp_use_efc? TPO_USE_EFC:0);
252 
253 				IFPERF(tpcb)
254 					u_char perf_meas = tpcb->tp_perf_on;
255 					ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
256 				ENDPERF
257 
258 				if( dutype == CR_TPDU_type ) {
259 					IncStat(ts_CR_sent);
260 
261 					ASSERT( tpcb->tp_lsuffixlen > 0 );
262 					ASSERT( tpcb->tp_fsuffixlen > 0 );
263 
264 					ADDOPTION(TPP_calling_sufx, hdr,
265 						tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
266 					ADDOPTION(TPP_called_sufx, hdr,
267 						tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
268 				} else {
269 					IncStat(ts_CC_sent);
270 				}
271 
272 				ADDOPTION(TPP_tpdu_size, hdr,
273 					sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
274 
275 				if (tpcb->tp_class != TP_CLASS_0) {
276 					short millisec = 500*(tpcb->tp_sendack_ticks);
277 
278 					millisec = htons(millisec);
279 					ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
280 
281 					x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
282 					 |	(tpcb->tp_use_rcc?  TPAO_USE_RCC : 0)
283 					 |  (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
284 					 |	(tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
285 					ADDOPTION(TPP_addl_opt, hdr, 1, x);
286 
287 					if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) {
288 						u_short size_s = tpcb->tp_l_tpdusize >> 7;
289 						u_char size_c = size_s;
290 						ASSERT(tpcb->tp_l_tpdusize < 65536 * 128);
291 						if (dutype == CR_TPDU_type)
292 							tpcb->tp_ptpdusize = size_s;
293 						if (size_s < 256) {
294 							ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
295 						} else {
296 							size_s = htons(size_s);
297 							ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s);
298 						}
299 					}
300 				}
301 
302 				if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
303 
304 					ASSERT( 1 == sizeof(tpcb->tp_vers) );
305 					ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
306 
307 					/* for each alt protocol class x,
308 					 * 	x = x<<4;
309 					 *  option = concat(option, x);
310 					 * Well, for now we only have TP0 for an
311 					 * alternative so... this is easy.
312 					 *
313 					 * HOWEVER... There should be NO alt protocol
314 					 * class over CLNS.  Need to see if the route suggests
315 					 * CONS, and iff so add alt class.
316 					 */
317 					x = 0;
318 					ADDOPTION(TPP_alt_class, hdr, 1, x);
319 				}
320 
321 				if( hdr->tpdu_li > MLEN)
322 					panic("tp_emit CR/CC");
323 			}
324 			break;
325 
326 		case DR_TPDU_type:
327 			if( hdr->tpdu_DRdref == 0 ) {
328 				/* don't issue the DR */
329 				goto done;
330 			}
331 			hdr->tpdu_cdt = 0;
332 			hdr->tpdu_DRsref = htons(tpcb->tp_lref);
333 			hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
334 
335 			/* forget the add'l information variable part */
336 			IncStat(ts_DR_sent);
337 			break;
338 
339 		case DC_TPDU_type: /* not used in class 0 */
340 			ASSERT( tpcb->tp_class != TP_CLASS_0);
341 			hdr->tpdu_DCsref =  htons(tpcb->tp_lref);
342 			hdr->tpdu_cdt = 0;
343 			data = (struct mbuf *)0;
344 			IncStat(ts_DC_sent);
345 			break;
346 
347 		case XAK_TPDU_type: /* xak not used in class 0 */
348 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
349 			hdr->tpdu_cdt = 0;
350 
351 			IFTRACE(D_XPD)
352 				tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
353 			ENDTRACE
354 			data = (struct mbuf *)0;
355 			if (tpcb->tp_xtd_format) {
356 #ifdef BYTE_ORDER
357 				union seq_type seqeotX;
358 
359 				seqeotX.s_seq = seq;
360 				seqeotX.s_eot = 1;
361 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
362 #else
363 				hdr->tpdu_XAKseqX = seq;
364 #endif BYTE_ORDER
365 			} else {
366 				hdr->tpdu_XAKseq = seq;
367 			}
368 			IncStat(ts_XAK_sent);
369 			IncPStat(tpcb, tps_XAK_sent);
370 			break;
371 
372 		case XPD_TPDU_type: /* xpd not used in class 0 */
373 			ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
374 			hdr->tpdu_cdt = 0;
375 			if (tpcb->tp_xtd_format) {
376 #ifdef BYTE_ORDER
377 				union seq_type seqeotX;
378 
379 				seqeotX.s_seq = seq;
380 				seqeotX.s_eot = 1;
381 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
382 #else
383 				hdr->tpdu_XPDseqX = seq;
384 				hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
385 #endif BYTE_ORDER
386 			} else {
387 				hdr->tpdu_XPDseq = seq;
388 				hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
389 			}
390 			IncStat(ts_XPD_sent);
391 			IncPStat(tpcb, tps_XPD_sent);
392 
393 			/* kludge to test the input size checking */
394 			IFDEBUG(D_SIZE_CHECK)
395 				/*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
396 					printf("Sending too much data on XPD: 18 bytes\n");
397 					data->m_len = 18;
398 				}*/
399 			ENDDEBUG
400 			break;
401 
402 		case DT_TPDU_type:
403 			hdr->tpdu_cdt = 0;
404 			IFTRACE(D_DATA)
405 				tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
406 					hdr->tpdu_li, 0);
407 			ENDTRACE
408 			if (tpcb->tp_xtd_format) {
409 #ifdef BYTE_ORDER
410 				union seq_type seqeotX;
411 
412 				seqeotX.s_seq = seq;
413 				seqeotX.s_eot = eot;
414 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
415 #else
416 				hdr->tpdu_DTseqX = seq;
417 				hdr->tpdu_DTeotX = eot;
418 #endif BYTE_ORDER
419 			} else if (tpcb->tp_class == TP_CLASS_0) {
420 				IFDEBUG(D_EMIT)
421 					printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
422 					dump_buf( hdr, hdr->tpdu_li + 1 );
423 				ENDDEBUG
424 				((struct tp0du *)hdr)->tp0du_eot = eot;
425 				((struct tp0du *)hdr)->tp0du_mbz = 0;
426 				IFDEBUG(D_EMIT)
427 					printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
428 					dump_buf( hdr, hdr->tpdu_li + 1 );
429 				ENDDEBUG
430 			} else {
431 				hdr->tpdu_DTseq = seq;
432 				hdr->tpdu_DTeot = eot;
433 			}
434 			if(eot) {
435 				IncStat(ts_EOT_sent);
436 			}
437 			IncStat(ts_DT_sent);
438 			IncPStat(tpcb, tps_DT_sent);
439 			break;
440 
441 		case AK_TPDU_type:/* ak not used in class 0 */
442 			ASSERT( tpcb->tp_class != TP_CLASS_0);
443 			data = (struct mbuf *)0;
444 			olduwe = tpcb->tp_sent_uwe;
445 
446 			if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
447 				LOCAL_CREDIT( tpcb );
448 				tpcb->tp_sent_uwe =
449 					SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
450 				tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
451 				acking_ooo = 0;
452 			} else
453 				acking_ooo = 1;
454 
455 			IFDEBUG(D_RENEG)
456 				/* occasionally fake a reneging so
457 					you can test subsequencing */
458 				if( olduwe & 0x1 ) {
459 					tpcb->tp_reneged = 1;
460 					IncStat(ts_ldebug);
461 				}
462 			ENDDEBUG
463 			/* Are we about to reneg on credit?
464 			 * When might we do so?
465 			 *	a) when using optimistic credit (which we no longer do).
466 			 *  b) when drain() gets implemented (not in the plans).
467 			 *  c) when D_RENEG is on.
468 			 *  d) when DEC BIT response is implemented.
469 			 *	(not- when we do this, we'll need to implement flow control
470 			 *	confirmation)
471 			 */
472 			if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
473 				tpcb->tp_reneged = 1;
474 				IncStat(ts_lcdt_reduced);
475 				IFTRACE(D_CREDIT)
476 					tptraceTPCB(TPPTmisc,
477 						"RENEG: olduwe newuwe lcredit rcvnxt",
478 						olduwe,
479 						tpcb->tp_sent_uwe, tpcb->tp_lcredit,
480 						tpcb->tp_rcvnxt);
481 				ENDTRACE
482 			}
483 			IFPERF(tpcb)
484 				/* new lwe is less than old uwe means we're
485 				 * acking before we received a whole window full
486 				 */
487 				if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
488 					/* tmp1 = number of pkts fewer than the full window */
489 					register int tmp1 =
490 						(int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
491 
492 					if(tmp1 > TP_PM_MAX)
493 						tmp1 = TP_PM_MAX;
494 					IncPStat( tpcb,  tps_ack_early[tmp1] );
495 
496 					/* tmp1 = amt of new cdt we're advertising */
497 					tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
498 					if(tmp1 > TP_PM_MAX )
499 						tmp1 = TP_PM_MAX;
500 
501 					IncPStat( tpcb,
502 							tps_cdt_acked [ tmp1 ]
503 							[ ((tpcb->tp_lcredit > TP_PM_MAX)?
504 								TP_PM_MAX:tpcb->tp_lcredit) ] );
505 
506 				}
507 			ENDPERF
508 
509 			IFTRACE(D_ACKSEND)
510 				tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
511 					tpcb->tp_r_subseq, 0);
512 			ENDTRACE
513 			if (tpcb->tp_xtd_format) {
514 #ifdef BYTE_ORDER
515 				union seq_type seqeotX;
516 
517 				seqeotX.s_seq = seq;
518 				seqeotX.s_eot = 0;
519 				hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
520 				hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
521 #else
522 				hdr->tpdu_cdt = 0;
523 				hdr->tpdu_AKseqX = seq;
524 				hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
525 #endif BYTE_ORDER
526 			} else {
527 				hdr->tpdu_AKseq = seq;
528 				hdr->tpdu_AKcdt = tpcb->tp_lcredit;
529 			}
530 			if ((tpcb->tp_class == TP_CLASS_4) &&
531 				(tpcb->tp_reneged || acking_ooo)) {
532 				/*
533 				 * Ack subsequence parameter req'd if WE reneged on
534 				 * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74)
535 				 */
536 				IFDEBUG(D_RENEG)
537 					printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
538 				ENDDEBUG
539 				tpcb->tp_s_subseq++;
540 				/*
541 				 * add tmp subseq and do a htons on it.
542 				 */
543 				ADDOPTION(TPP_subseq, hdr,
544 					sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
545 			} else
546 				tpcb->tp_s_subseq = 0;
547 
548 			if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
549 				/*
550 				 * Rules for sending FCC ("should" send when) :
551 				 * %a) received an ack from peer with NO NEWS whatsoever,
552 				 *  	and it did not contain an FCC
553 				 * 	b) received an ack from peer that opens its closed window.
554 				 * 	c) received an ack from peer after it reneged on its
555 				 *		offered credit, AND this ack raises UWE but LWE is same
556 				 *		and below UWE at time of reneging (reduction)
557 				 * Now, ISO 8073 12.2.3.8.3 says
558 				 * that a retransmitted AK shall not contain the FCC
559 				 * parameter.  Now, how the hell you tell the difference
560 				 * between a retransmitted ack and an ack that's sent in
561 				 * response to a received ack, I don't know, because without
562 				 * any local activity, and w/o any received DTs, they
563 				 * will contain exactly the same credit/seq# information.
564 				 * Anyway, given that the "retransmission of acks"
565 				 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
566 				 * don't do it (although the peer can't tell that), we
567 				 * ignore this last rule.
568 				 *
569 				 * We send FCC for reasons a) and b) only.
570 				 * To add reason c) would require a ridiculous amount of state.
571 				 *
572 				 */
573 				u_short 	bogus[4]; /* lwe(32), subseq(16), cdt(16) */
574 				SeqNum		lwe;
575 				u_short		subseq, fcredit;
576 
577 				tpcb->tp_sendfcc = 0;
578 
579 				lwe = (SeqNum) htonl(tpcb->tp_snduna);
580 				subseq = htons(tpcb->tp_r_subseq);
581 				fcredit = htons(tpcb->tp_fcredit);
582 
583 				bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
584 				bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
585 				bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
586 
587 				IFTRACE(D_ACKSEND)
588 					tptraceTPCB(TPPTmisc,
589 						"emit w/FCC: snduna r_subseq fcredit",
590 						tpcb->tp_snduna, tpcb->tp_r_subseq,
591 						tpcb->tp_fcredit, 0);
592 				ENDTRACE
593 
594 				IFDEBUG(D_ACKSEND)
595 					printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
596 						TPP_flow_cntl_conf,
597 						hdr, sizeof(bogus), bogus[0]);
598 				ENDDEBUG
599 				ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
600 				IFDEBUG(D_ACKSEND)
601 					printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
602 						hdr, hdr->tpdu_li);
603 					printf(
604 					"after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
605 							csum_offset, hdr->tpdu_li);
606 				ENDDEBUG
607 
608 			}
609 			tpcb->tp_reneged = 0;
610 			tpcb->tp_sent_rcvnxt = seq;
611 			if (tpcb->tp_fcredit == 0) {
612 				int timo = tpcb->tp_keepalive_ticks;
613 				if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
614 					tpcb->tp_rxtshift++;
615 				timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
616 				tp_ctimeout(tpcb, TM_sendack, timo);
617 			} else
618 				tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
619 			IncStat(ts_AK_sent);
620 			IncPStat(tpcb, tps_AK_sent);
621 			IFDEBUG(D_ACKSEND)
622 				printf(
623 				"2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
624 						csum_offset, hdr->tpdu_li);
625 			ENDDEBUG
626 			break;
627 
628 		case ER_TPDU_type:
629 			hdr->tpdu_ERreason = eot;
630 			hdr->tpdu_cdt = 0;
631 			/* no user data */
632 			data = (struct mbuf *)0;
633 			IncStat(ts_ER_sent);
634 			break;
635 		}
636 
637 	}
638 	ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
639 
640 	m->m_next = data;
641 
642 	ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
643 	ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
644 
645 	m->m_len = hdr->tpdu_li ;
646 	hdr->tpdu_li --; /* doesn't include the li field */
647 
648 	datalen = m_datalen( m ); /* total len */
649 
650 	ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
651 				when CLNP is used; leave in here for the time being */
652 		IFDEBUG(D_ACKSEND)
653 			printf(
654 			"4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
655 					csum_offset, hdr->tpdu_li);
656 		ENDDEBUG
657 	if( datalen > tpcb->tp_l_tpdusize ) {
658 		printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
659 			datalen, tpcb->tp_l_tpdusize);
660 	}
661 	IFDEBUG(D_EMIT)
662 		printf(
663 		"tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
664 		m->m_len, csum_offset, datalen);
665 	ENDDEBUG
666 	if( tpcb->tp_use_checksum ||
667 		(dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
668 		iso_gen_csum(m, csum_offset, datalen);
669 	}
670 
671 	IFDEBUG(D_EMIT)
672 	printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
673 		tpcb, dutype, datalen);
674 		dump_buf(mtod(m, caddr_t), datalen);
675 	ENDDEBUG
676 
677 	IFPERF(tpcb)
678 		if( dutype == DT_TPDU_type ) {
679 			PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
680 			tpmeas( tpcb->tp_lref, TPtime_to_ll,  (struct timeval *)0,
681 				seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
682 		}
683 	ENDPERF
684 
685 	IFTRACE(D_EMIT)
686 		tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
687 	ENDTRACE
688 	IFDEBUG(D_EMIT)
689 		printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
690 			tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
691 	ENDDEBUG
692 
693 	{ extern char tp_delay;
694 
695 		if( tp_delay )
696 			if( tpcb->tp_use_checksum == 0 ) {
697 				register u_int i  = tp_delay;
698 				for (; i!= 0; i--)
699 					(void) iso_check_csum(m, datalen);
700 			}
701 	}
702 	ASSERT( m->m_len > 0 );
703 	error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
704 		!tpcb->tp_use_checksum);
705 	IFDEBUG(D_EMIT)
706 		printf("OUTPUT: returned 0x%x\n", error);
707 	ENDDEBUG
708 	IFTRACE(D_EMIT)
709 		tptraceTPCB(TPPTmisc,
710 			"tp_emit nlproto->output netservice returns datalen",
711 			tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
712 	ENDTRACE
713 done:
714 	if (error) {
715 		if (dutype == AK_TPDU_type)
716 			tp_ctimeout(tpcb, TM_sendack, 1);
717 		if (error == E_CO_QFULL) {
718 			tp_quench(tpcb, PRC_QUENCH);
719 			return 0;
720 		}
721 	}
722 	return error;
723 }
724 /*
725  * NAME:		tp_error_emit()
726  * CALLED FROM:	tp_input() when a DR or ER is to be issued in
727  * 		response to an input error.
728  * FUNCTION and ARGUMENTS:
729  * 		The error type is the first argument.
730  * 		The argument (sref) is the source reference on the bad incoming tpdu,
731  * 		and is used for a destination reference on the outgoing packet.
732  * 		(faddr) and (laddr) are the foreign and local addresses for this
733  *		connection.
734  * 		(erdata) is a ptr to the errant incoming tpdu, and is copied into the
735  * 		outgoing ER, if an ER is to be issued.
736  * 		(erlen)  is the number of octets of the errant tpdu that we should
737  * 		try to copy.
738  * 		(tpcb) is the pcb that describes the connection for which the bad tpdu
739  * 		arrived.
740  * RETURN VALUES:
741  * 		0 OK
742  *  	ENOBUFS
743  *  	E* from net layer datagram output routine
744  * SIDE EFFECTS:
745  *
746  * NOTES:
747  */
748 
749 int
750 tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
751 	dgout_routine)
752 	int				error;
753 	u_long			sref;
754 	struct sockaddr_iso *faddr, *laddr;
755 	struct mbuf 	*erdata;
756 	int 			erlen;
757 	struct tp_pcb 	*tpcb;
758 	caddr_t			cons_channel;
759 	int				(*dgout_routine)();
760 {
761 	int						dutype;
762 	int 					datalen = 0;
763 	register struct tpdu	*hdr;
764 	register struct mbuf	*m;
765 	int						csum_offset;
766 
767 	IFTRACE(D_ERROR_EMIT)
768 		tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
769 			error, sref, tpcb, erlen);
770 	ENDTRACE
771 	IFDEBUG(D_ERROR_EMIT)
772 		printf(
773 		"tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
774 			error, sref, tpcb, erlen, cons_channel);
775 	ENDDEBUG
776 
777 	MGET(m, M_DONTWAIT, TPMT_TPHDR);
778 	if (m == NULL) {
779 		return ENOBUFS;
780 	}
781 	m->m_len = sizeof(struct tpdu);
782 	m->m_act = MNULL;
783 
784 	hdr = mtod(m, struct tpdu *);
785 
786 	IFDEBUG(D_ERROR_EMIT)
787 		printf("[error 0x%x] [error&0xff  0x%x] [(char)error 0x%x]\n",
788 			error, error&0xff, (char)error);
789 	ENDDEBUG
790 
791 
792 	if (error & TP_ERROR_SNDC)
793 		dutype = DC_TPDU_type;
794 	else if (error & 0x40) {
795 		error &= ~0x40;
796 		dutype = ER_TPDU_type;
797 	} else
798 		dutype = DR_TPDU_type;
799 	error &= 0xff;
800 
801 	hdr->tpdu_type = dutype;
802 	hdr->tpdu_cdt = 0;
803 
804 	switch( dutype ) {
805 
806 	case DC_TPDU_type:
807 		IncStat(ts_DC_sent);
808 		hdr->tpdu_li = 6;
809 		hdr->tpdu_DCdref = htons(sref);
810 		hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
811 		IFDEBUG(D_ERROR_EMIT)
812 			printf("DC case:\n");
813 			dump_buf( hdr, 6);
814 		ENDDEBUG
815 		/* forget the add'l information variable part */
816 		break;
817 
818 	case DR_TPDU_type:
819 		IncStat(ts_DR_sent);
820 		hdr->tpdu_li = 7;
821 		hdr->tpdu_DRdref = htons(sref);
822 		hdr->tpdu_DRsref = 0;
823 		hdr->tpdu_DRreason = (char)error;
824 		IFDEBUG(D_ERROR_EMIT)
825 			printf("DR case:\n");
826 			dump_buf( hdr, 7);
827 		ENDDEBUG
828 		/* forget the add'l information variable part */
829 		break;
830 
831 	case ER_TPDU_type:
832 		IncStat(ts_ER_sent);
833 		hdr->tpdu_li = 5;
834 		hdr->tpdu_ERreason = (char)error;
835 		hdr->tpdu_ERdref = htons(sref);
836 		break;
837 
838 	default:
839 		ASSERT(0);
840 		printf("TP PANIC: bad dutype 0x%x\n", dutype);
841 	}
842 
843 	if(tpcb)
844 		if( tpcb->tp_use_checksum ) {
845 			ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
846 			csum_offset =  hdr->tpdu_li - 2;
847 		}
848 
849 	ASSERT( hdr->tpdu_li < MLEN );
850 
851 	if (dutype == ER_TPDU_type) {
852 		/* copy the errant tpdu into another 'variable part' */
853 		register caddr_t P;
854 
855 		IFTRACE(D_ERROR_EMIT)
856 			tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
857 				0,0);
858 		ENDTRACE
859 		IFDEBUG(D_ERROR_EMIT)
860 			printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
861 		ENDDEBUG
862 
863 		/* copy at most as many octets for which you have room */
864 		if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
865 			erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
866 
867 		/* add the "invalid tpdu" parameter : required in class 0 */
868 		P = (caddr_t)hdr + (int)(hdr->tpdu_li);
869 		vbptr(P)->tpv_code =  TPP_invalid_tpdu; /* parameter code */
870 		vbptr(P)->tpv_len = erlen;	/* parameter length */
871 		m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
872 
873 		/* tp_input very likely handed us an mbuf chain w/ nothing in
874 		 * the first mbuf and the data following the empty mbuf
875 		 */
876 		if(erdata->m_len == 0) {
877 			erdata = m_free(erdata); /* returns the next mbuf on the chain */
878 		}
879 		/*
880 		 * copy only up to the bad octet
881 		 * (or max that will fit in a header
882 		 */
883 		m->m_next = m_copy(erdata, 0, erlen);
884 		hdr->tpdu_li += erlen + 2;
885 		m_freem(erdata);
886 	} else {
887 		IFDEBUG(D_ERROR_EMIT)
888 			printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
889 			dump_buf( (char *)hdr, hdr->tpdu_li );
890 		ENDDEBUG
891 		m->m_len = hdr->tpdu_li ;
892 		m_freem(erdata);
893 	}
894 
895 	hdr->tpdu_li --;
896 	IFTRACE(D_ERROR_EMIT)
897 		tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
898 	ENDTRACE
899 
900 	datalen = m_datalen( m);
901 	if (tpcb) {
902 		if( tpcb->tp_use_checksum ) {
903 			IFTRACE(D_ERROR_EMIT)
904 				tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
905 			ENDTRACE
906 			IFDEBUG(D_ERROR_EMIT)
907 				printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
908 					datalen, csum_offset);
909 			ENDDEBUG
910 
911 			iso_gen_csum(m, csum_offset, datalen);
912 		}
913 
914 		IFDEBUG(D_ERROR_EMIT)
915 			printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
916 				tpcb,  tpcb->tp_npcb,  tpcb->tp_sock);
917 		ENDDEBUG
918 	}
919 	if (cons_channel) {
920 #ifdef TPCONS
921 		struct pklcd *lcp = (struct pklcd *)cons_channel;
922 		struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext;
923 
924 		tpcons_dg_output(cons_channel, m, datalen);
925 		/* was if (tpcb == 0) iso_pcbdetach(isop); */
926 		/* but other side may want to try again over same VC,
927 		   so, we'll depend on him closing it, but in case it gets forgotten
928 		   we'll mark it for garbage collection */
929 		lcp->lcd_flags |= X25_DG_CIRCUIT;
930 		IFDEBUG(D_ERROR_EMIT)
931 			printf("OUTPUT: dutype 0x%x channel 0x%x\n",
932 				dutype, cons_channel);
933 		ENDDEBUG
934 #else
935 		printf("TP panic! cons channel 0x%x but not cons configured\n",
936 			cons_channel);
937 #endif
938 	} else if (tpcb) {
939 
940 		IFDEBUG(D_ERROR_EMIT)
941 			printf("tp_error_emit 1 sending DG: Laddr\n");
942 			dump_addr((struct sockaddr *)laddr);
943 			printf("Faddr\n");
944 			dump_addr((struct sockaddr *)faddr);
945 		ENDDEBUG
946 		return (tpcb->tp_nlproto->nlp_dgoutput)(
947 			&laddr->siso_addr,
948 			&faddr->siso_addr,
949 			m, datalen,
950 					/* no route */	(caddr_t)0, !tpcb->tp_use_checksum);
951 	} else if (dgout_routine) {
952 			IFDEBUG(D_ERROR_EMIT)
953 				printf("tp_error_emit sending DG: Laddr\n");
954 				dump_addr((struct sockaddr *)laddr);
955 				printf("Faddr\n");
956 				dump_addr((struct sockaddr *)faddr);
957 			ENDDEBUG
958 				return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
959 					m, datalen, /* no route */
960 					(caddr_t)0, /* nochecksum==false */0);
961 	} else {
962 			IFDEBUG(D_ERROR_EMIT)
963 				printf("tp_error_emit DROPPING \n", m);
964 			ENDDEBUG
965 			IncStat(ts_send_drop);
966 			m_freem(m);
967 			return 0;
968 	}
969 }
970