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