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