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