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