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