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