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