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