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