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