file modes have to agree
[unix-history] / usr / src / sys / netiso / tp_emit.c
CommitLineData
f04c49fa
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
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
48static 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
73void 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 */
80char 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
125int
126tp_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
642done:
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
675int
676tp_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}