1 /* $NetBSD: tp_emit.c,v 1.29 2009/03/18 17:06:53 cegger Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * This file contains tp_emit() and tp_error_emit(), which form TPDUs and
62 * hand them to ip. They take data in the form of mbuf chain, allocate mbufs
63 * as necessary for headers, and set the fields as appropriate from
64 * information found in the tpcb and net-level pcb.
66 * The worst thing about this code is adding the variable-length options on a
67 * machine that requires alignment for any memory access that isn't of size
68 * 1. See the macro ADDOPTION() below.
70 * We don't do any concatenation. (There's a kludge to test the basic mechanism
71 * of separation under the 'w' tpdebug option, that's all.)
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: tp_emit.c,v 1.29 2009/03/18 17:06:53 cegger Exp $");
79 #include <sys/param.h>
80 #include <sys/systm.h>
82 #include <sys/socket.h>
83 #include <sys/socketvar.h>
84 #include <sys/protosw.h>
85 #include <sys/errno.h>
90 #include <netiso/iso.h>
91 #include <netiso/iso_pcb.h>
92 #include <netiso/argo_debug.h>
93 #include <netiso/tp_timer.h>
94 #include <netiso/tp_param.h>
95 #include <netiso/tp_stat.h>
96 #include <netiso/tp_pcb.h>
97 #include <netiso/tp_tpdu.h>
98 #include <netiso/tp_trace.h>
99 #include <netiso/tp_meas.h>
100 #include <netiso/tp_seq.h>
101 #include <netiso/tp_var.h>
102 #include <netiso/iso_errno.h>
103 #include <netiso/iso_var.h>
106 * Here is a mighty kludge. The token ring misorders packets if you fire
107 * them at it too fast, and TP sans checksum is "too fast", so we have
108 * introduced a delay when checksumming isn't used.
110 char tp_delay
= 0x00;/* delay to keep token ring from blowing it */
115 * CALLED FROM: tp.trans and from tp_sbsend()
117 * FUNCTION and ARGUMENTS:
118 * Emits one tpdu of the type (dutype), of the format appropriate
119 * to the connection described by the pcb (tpcb), with sequence
120 * number (seq) (where appropriate), end-of-tsdu bit (eot) where
121 * appropriate, and with the data in the mbuf chain (data).
122 * For DR and ER tpdus, the argument (eot) is
123 * the reason for issuing the tpdu rather than an end-of-tsdu indicator.
128 * E* returned from net layer output rtn
134 * WE ASSUME that the tp header + all options will fit in ONE mbuf.
135 * If mbufs are 256 this will most likely be true, but if they are 128 it's
136 * possible that they won't.
137 * If you used every option on the CR + max. user data you'd overrun
138 * 112 but unless you used > 115 bytes for the security
139 * parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
140 * We don't support the security parameter, so this isn't a problem.
141 * If security is added, we ought to remove this assumption.
143 * We do not implement the flow control confirmation "element of procedure".
144 * A) it should not affect interoperability,
145 * B) it should not be necessary - the protocol will eventually
146 * straighten things out w/o FCC, as long as we don't have severely
147 * mismatched keepalive and inactivity timers, and
148 * C) it appears not to be REQUIRED, and
149 * D) it's incredibly grotesque, and no doubt will lengthen a few
151 * HOWEVER, we're thinking about putting it in anyway, for
152 * completeness, just like we did with ack subsequencing.
172 * NOTE: here we treat tpdu_li as if it DID include the li field, up
173 * until the end, at which time we subtract 1 THis is because if we
174 * subtract 1 right away, we end up adding one every time we add an
178 if (argo_debug
[D_EMIT
]) {
180 "tp_emit dutype 0x%x, tpcb %p, eot 0x%x, seq 0x%x, data %p",
181 dutype
, tpcb
, eot
, seq
, data
);
185 if (dutype
== CR_TPDU
|| dutype
== CC_TPDU
) {
186 m
= (struct mbuf
*) malloc((u_long
) 256, M_MBUF
, M_DONTWAIT
);
188 m
->m_type
= TPMT_TPHDR
;
189 mbstat
.m_mtypes
[TPMT_TPHDR
]++;
192 m
->m_data
= m
->m_pktdat
;
193 m
->m_flags
= M_PKTHDR
;
194 memset(&m
->m_pkthdr
, 0, sizeof(m
->m_pkthdr
));
197 MGETHDR(m
, M_DONTWAIT
, TPMT_TPHDR
);
200 if (data
!= (struct mbuf
*) 0)
205 m
->m_data
+= max_hdr
;
206 m
->m_len
= sizeof(struct tpdu
);
209 hdr
= mtod(m
, struct tpdu
*);
210 memset((void *) hdr
, 0, sizeof(struct tpdu
));
213 hdr
->tpdu_type
= dutype
;
214 hdr
->tpdu_li
= tp_headersize(dutype
, tpcb
);
216 * class 0 doesn't use this for DT
217 * it'll just get overwritten below
219 hdr
->tpdu_dref
= htons(tpcb
->tp_fref
);
220 if (tpcb
->tp_use_checksum
||
221 (dutype
== CR_TPDU_type
&& (tpcb
->tp_class
& TP_CLASS_4
))) {
222 csum_offset
= hdr
->tpdu_li
+ 2; /* DOESN'T include csum */
223 ADDOPTION(TPP_checksum
, hdr
, 2, eot
/* dummy arg */ );
225 if (argo_debug
[D_CHKSUM
]) {
227 "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
228 csum_offset
, hdr
->tpdu_li
);
238 hdr
->tpdu_CRdref_0
= 0; /* must be zero */
240 if (!tpcb
->tp_cebit_off
) {
241 tpcb
->tp_win_recv
= tp_start_win
<< 8;
243 CONG_INIT_SAMPLE(tpcb
);
247 /* Case CC_TPDU_type used to be here */
251 hdr
->tpdu_CCsref
= htons(tpcb
->tp_lref
); /* same as CRsref */
253 if (tpcb
->tp_class
> TP_CLASS_1
) {
254 tpcb
->tp_sent_uwe
= tpcb
->tp_lcredit
- 1;
255 tpcb
->tp_sent_rcvnxt
= 1;
256 tpcb
->tp_sent_lcdt
= tpcb
->tp_lcredit
;
257 hdr
->tpdu_cdt
= tpcb
->tp_lcredit
;
261 hdr
->tpdu_CCclass
= tp_mask_to_num(tpcb
->tp_class
);
262 hdr
->tpdu_CCoptions
=
263 (tpcb
->tp_xtd_format
? TPO_XTD_FMT
: 0) |
264 (tpcb
->tp_use_efc
? TPO_USE_EFC
: 0);
268 u_char perf_meas
= tpcb
->tp_perf_on
;
269 ADDOPTION(TPP_perf_meas
, hdr
,
270 sizeof(perf_meas
), perf_meas
);
274 if (dutype
== CR_TPDU_type
) {
277 ASSERT(tpcb
->tp_lsuffixlen
> 0);
278 ASSERT(tpcb
->tp_fsuffixlen
> 0);
280 ADDOPTION(TPP_calling_sufx
, hdr
,
281 tpcb
->tp_lsuffixlen
, tpcb
->tp_lsuffix
[0]);
282 ADDOPTION(TPP_called_sufx
, hdr
,
283 tpcb
->tp_fsuffixlen
, tpcb
->tp_fsuffix
[0]);
288 ADDOPTION(TPP_tpdu_size
, hdr
,
289 sizeof(tpcb
->tp_tpdusize
), tpcb
->tp_tpdusize
);
291 if (tpcb
->tp_class
!= TP_CLASS_0
) {
292 short millisec
= 500 * (tpcb
->tp_sendack_ticks
);
294 millisec
= htons(millisec
);
295 ADDOPTION(TPP_acktime
, hdr
, sizeof(short), millisec
);
297 x
= (tpcb
->tp_use_nxpd
? TPAO_USE_NXPD
: 0)
298 | (tpcb
->tp_use_rcc
? TPAO_USE_RCC
: 0)
299 | (tpcb
->tp_use_checksum
? 0 : TPAO_NO_CSUM
)
300 | (tpcb
->tp_xpd_service
? TPAO_USE_TXPD
: 0);
301 ADDOPTION(TPP_addl_opt
, hdr
, 1, x
);
303 if ((tpcb
->tp_l_tpdusize
^ (1 << tpcb
->tp_tpdusize
)) != 0) {
304 u_short size_s
= tpcb
->tp_l_tpdusize
>> 7;
305 u_char size_c
= size_s
;
306 ASSERT(tpcb
->tp_l_tpdusize
< 65536 * 128);
307 if (dutype
== CR_TPDU_type
)
308 tpcb
->tp_ptpdusize
= size_s
;
310 ADDOPTION(TPP_ptpdu_size
, hdr
, 1, size_c
);
312 size_s
= htons(size_s
);
313 ADDOPTION(TPP_ptpdu_size
, hdr
, 2, size_s
);
317 if ((dutype
== CR_TPDU_type
) && (tpcb
->tp_class
!= TP_CLASS_0
)) {
319 ASSERT(1 == sizeof(tpcb
->tp_vers
));
320 ADDOPTION(TPP_vers
, hdr
, 1, tpcb
->tp_vers
);
323 * for each alt protocol class x, x =
324 * x<<4; option = concat(option, x);
325 * Well, for now we only have TP0 for
326 * an alternative so... this is easy.
328 * HOWEVER... There should be NO alt
329 * protocol class over CLNS. Need to
330 * see if the route suggests CONS,
331 * and iff so add alt class.
334 ADDOPTION(TPP_alt_class
, hdr
, 1, x
);
337 if (hdr
->tpdu_li
> MLEN
)
338 panic("tp_emit CR/CC");
344 if (hdr
->tpdu_DRdref
== 0) {
345 /* don't issue the DR */
349 hdr
->tpdu_DRsref
= htons(tpcb
->tp_lref
);
350 hdr
->tpdu_DRreason
= (u_char
) eot
; /* WHICH BYTE OF THIS??? */
352 /* forget the add'l information variable part */
356 case DC_TPDU_type
: /* not used in class 0 */
357 ASSERT(tpcb
->tp_class
!= TP_CLASS_0
);
358 hdr
->tpdu_DCsref
= htons(tpcb
->tp_lref
);
360 data
= (struct mbuf
*) 0;
364 case XAK_TPDU_type
: /* xak not used in class 0 */
365 ASSERT(tpcb
->tp_class
!= TP_CLASS_0
); /* fall through */
369 if (tp_traceflags
[D_XPD
]) {
370 tptraceTPCB(TPPTXack
, seq
, 0, 0, 0, 0);
373 data
= (struct mbuf
*) 0;
374 if (tpcb
->tp_xtd_format
) {
376 union seq_type seqeotX
;
380 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
382 hdr
->tpdu_XAKseqX
= seq
;
383 #endif /* BYTE_ORDER */
385 hdr
->tpdu_XAKseq
= seq
;
387 IncStat(ts_XAK_sent
);
388 IncPStat(tpcb
, tps_XAK_sent
);
391 case XPD_TPDU_type
: /* xpd not used in class 0 */
392 ASSERT(tpcb
->tp_class
!= TP_CLASS_0
); /* fall through */
394 if (tpcb
->tp_xtd_format
) {
396 union seq_type seqeotX
;
400 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
402 hdr
->tpdu_XPDseqX
= seq
;
403 hdr
->tpdu_XPDeotX
= 1; /* always 1 for XPD tpdu */
404 #endif /* BYTE_ORDER */
406 hdr
->tpdu_XPDseq
= seq
;
407 hdr
->tpdu_XPDeot
= 1; /* always 1 for XPD tpdu */
409 IncStat(ts_XPD_sent
);
410 IncPStat(tpcb
, tps_XPD_sent
);
412 /* kludge to test the input size checking */
414 if (argo_debug
[D_SIZE_CHECK
]) {
416 if (data
->m_len
<= 16 &&
417 data
->m_off
< (MLEN
-18)) {
418 printf("Sending too much data on XPD: 18 bytes\n");
429 if (tp_traceflags
[D_DATA
]) {
430 tptraceTPCB(TPPTmisc
,
431 "emit DT: eot seq tpdu_li", eot
,
432 seq
, hdr
->tpdu_li
, 0);
435 if (tpcb
->tp_xtd_format
) {
437 union seq_type seqeotX
;
441 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
443 hdr
->tpdu_DTseqX
= seq
;
444 hdr
->tpdu_DTeotX
= eot
;
445 #endif /* BYTE_ORDER */
446 } else if (tpcb
->tp_class
== TP_CLASS_0
) {
448 if (argo_debug
[D_EMIT
]) {
449 printf("DT tpdu: class 0 m %p hdr %p\n", m
, hdr
);
450 dump_buf(hdr
, hdr
->tpdu_li
+ 1);
453 ((struct tp0du
*) hdr
)->tp0du_eot
= eot
;
454 ((struct tp0du
*) hdr
)->tp0du_mbz
= 0;
456 if (argo_debug
[D_EMIT
]) {
457 printf("DT 2 tpdu: class 0 m %p hdr %p\n", m
, hdr
);
458 dump_buf(hdr
, hdr
->tpdu_li
+ 1);
462 hdr
->tpdu_DTseq
= seq
;
463 hdr
->tpdu_DTeot
= eot
;
466 IncStat(ts_EOT_sent
);
469 IncPStat(tpcb
, tps_DT_sent
);
472 case AK_TPDU_type
: /* ak not used in class 0 */
473 ASSERT(tpcb
->tp_class
!= TP_CLASS_0
);
474 data
= (struct mbuf
*) 0;
475 olduwe
= tpcb
->tp_sent_uwe
;
477 if (seq
!= tpcb
->tp_sent_rcvnxt
|| tpcb
->tp_rsycnt
== 0) {
480 SEQ(tpcb
, tpcb
->tp_rcvnxt
+ tpcb
->tp_lcredit
- 1);
481 tpcb
->tp_sent_lcdt
= tpcb
->tp_lcredit
;
487 if (argo_debug
[D_RENEG
]) {
489 * occasionally fake a reneging so you can test
493 tpcb
->tp_reneged
= 1;
499 * Are we about to reneg on credit? When might we do
500 * so? a) when using optimistic credit (which we no
501 * longer do). b) when drain() gets implemented (not
502 * in the plans). c) when D_RENEG is on. d) when DEC
503 * BIT response is implemented. (not- when we do
504 * this, we'll need to implement flow control
507 if (SEQ_LT(tpcb
, tpcb
->tp_sent_uwe
, olduwe
)) {
508 tpcb
->tp_reneged
= 1;
509 IncStat(ts_lcdt_reduced
);
511 if (tp_traceflags
[D_CREDIT
]) {
512 tptraceTPCB(TPPTmisc
,
513 "RENEG: olduwe newuwe lcredit rcvnxt",
515 tpcb
->tp_sent_uwe
, tpcb
->tp_lcredit
,
523 * new lwe is less than old uwe means we're
524 * acking before we received a whole window full
526 if (SEQ_LT(tpcb
, tpcb
->tp_rcvnxt
, olduwe
)) {
528 * tmp1 = number of pkts fewer than
532 (int) SEQ_SUB(tpcb
, olduwe
,
535 if (tmp1
> TP_PM_MAX
)
537 IncPStat(tpcb
, tps_ack_early
[tmp1
]);
540 * tmp1 = amt of new cdt we're
543 tmp1
= SEQ_SUB(tpcb
, seq
,
544 tpcb
->tp_sent_rcvnxt
);
545 if (tmp1
> TP_PM_MAX
)
550 [((tpcb
->tp_lcredit
>
560 if (tp_traceflags
[D_ACKSEND
]) {
561 tptraceTPCB(TPPTack
, seq
, tpcb
->tp_lcredit
,
563 tpcb
->tp_r_subseq
, 0);
566 if (tpcb
->tp_xtd_format
) {
568 union seq_type seqeotX
;
572 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
573 hdr
->tpdu_AKcdtX
= htons(tpcb
->tp_lcredit
);
576 hdr
->tpdu_AKseqX
= seq
;
577 hdr
->tpdu_AKcdtX
= tpcb
->tp_lcredit
;
578 #endif /* BYTE_ORDER */
580 hdr
->tpdu_AKseq
= seq
;
581 hdr
->tpdu_AKcdt
= tpcb
->tp_lcredit
;
583 if ((tpcb
->tp_class
== TP_CLASS_4
) &&
584 (tpcb
->tp_reneged
|| acking_ooo
)) {
586 * Ack subsequence parameter req'd if WE
587 * reneged on credit offered. (ISO 8073,
591 if (argo_debug
[D_RENEG
]) {
592 printf("Adding subseq 0x%x\n", tpcb
->tp_s_subseq
);
597 * add tmp subseq and do a htons on it.
599 ADDOPTION(TPP_subseq
, hdr
,
600 sizeof(tpcb
->tp_s_subseq
), tpcb
->tp_s_subseq
);
602 tpcb
->tp_s_subseq
= 0;
604 if (tpcb
->tp_sendfcc
|| eot
) { /* overloaded to mean
607 * Rules for sending FCC ("should" send when)
608 * : %a) received an ack from peer with NO
609 * NEWS whatsoever, and it did not contain an
610 * FCC b) received an ack from peer that
611 * opens its closed window. c) received an
612 * ack from peer after it reneged on its
613 * offered credit, AND this ack raises UWE
614 * but LWE is same and below UWE at time of
615 * reneging (reduction) Now, ISO 8073
616 * 12.2.3.8.3 says that a retransmitted AK
617 * shall not contain the FCC parameter. Now,
618 * how the hell you tell the difference
619 * between a retransmitted ack and an ack
620 * that's sent in response to a received ack,
621 * I don't know, because without any local
622 * activity, and w/o any received DTs, they
623 * will contain exactly the same credit/seq#
624 * information. Anyway, given that the
625 * "retransmission of acks" procedure (ISO
626 * 8073 12.2.3.8.3) is optional, and we don't
627 * do it (although the peer can't tell that),
628 * we ignore this last rule.
630 * We send FCC for reasons a) and b) only. To
631 * add reason c) would require a ridiculous
635 u_short bogus
[4]; /* lwe(32), subseq(16),
638 u_short subseq
, fcredit
;
640 tpcb
->tp_sendfcc
= 0;
642 lwe
= (SeqNum
) htonl(tpcb
->tp_snduna
);
643 subseq
= htons(tpcb
->tp_r_subseq
);
644 fcredit
= htons(tpcb
->tp_fcredit
);
646 memcpy((void *) & bogus
[0], (void *) & lwe
, sizeof(SeqNum
));
647 memcpy((void *) & bogus
[2], (void *) & subseq
, sizeof(u_short
));
648 memcpy((void *) & bogus
[3], (void *) & fcredit
, sizeof(u_short
));
651 if (tp_traceflags
[D_ACKSEND
]) {
652 tptraceTPCB(TPPTmisc
,
653 "emit w/FCC: snduna r_subseq fcredit",
654 tpcb
->tp_snduna
, tpcb
->tp_r_subseq
,
655 tpcb
->tp_fcredit
, 0);
660 if (argo_debug
[D_ACKSEND
]) {
661 printf("Calling ADDOPTION 0x%x, %p, 0x%lx,0x%x\n",
663 hdr
, (unsigned long)sizeof(bogus
), bogus
[0]);
666 ADDOPTION(TPP_flow_cntl_conf
, hdr
, sizeof(bogus
), bogus
[0]);
668 if (argo_debug
[D_ACKSEND
]) {
669 printf("after ADDOPTION hdr %p hdr->tpdu_li 0x%x\n",
672 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
673 csum_offset
, hdr
->tpdu_li
);
678 tpcb
->tp_reneged
= 0;
679 tpcb
->tp_sent_rcvnxt
= seq
;
680 if (tpcb
->tp_fcredit
== 0) {
681 int timo
= tpcb
->tp_keepalive_ticks
;
682 if (tpcb
->tp_rxtshift
< TP_MAXRXTSHIFT
)
684 timo
= min(timo
, ((int) tpcb
->tp_dt_ticks
) << tpcb
->tp_rxtshift
);
685 tp_ctimeout(tpcb
, TM_sendack
, timo
);
687 tp_ctimeout(tpcb
, TM_sendack
, tpcb
->tp_keepalive_ticks
);
689 IncPStat(tpcb
, tps_AK_sent
);
691 if (argo_debug
[D_ACKSEND
]) {
693 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
694 csum_offset
, hdr
->tpdu_li
);
700 hdr
->tpdu_ERreason
= eot
;
703 data
= (struct mbuf
*) 0;
709 ASSERT((int) hdr
->tpdu_li
!= 0);
711 ASSERT((int) hdr
->tpdu_li
< MLEN
);
717 ASSERT(hdr
->tpdu_li
< MLEN
); /* leave this in */
719 ASSERT(hdr
->tpdu_li
!= 0); /* leave this in */
721 m
->m_len
= hdr
->tpdu_li
;
722 hdr
->tpdu_li
--; /* doesn't include the li field */
724 datalen
= m_datalen(m
); /* total len */
726 ASSERT(datalen
<= tpcb
->tp_l_tpdusize
); /* may become a problem when
727 * CLNP is used; leave in
728 * here for the time being */
730 if (argo_debug
[D_ACKSEND
]) {
732 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
733 csum_offset
, hdr
->tpdu_li
);
736 if (datalen
> tpcb
->tp_l_tpdusize
) {
737 printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
738 datalen
, tpcb
->tp_l_tpdusize
);
741 if (argo_debug
[D_EMIT
]) {
743 "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
744 m
->m_len
, csum_offset
, datalen
);
747 if (tpcb
->tp_use_checksum
||
748 (dutype
== CR_TPDU_type
&& (tpcb
->tp_class
& TP_CLASS_4
))) {
749 iso_gen_csum(m
, csum_offset
, datalen
);
752 if (argo_debug
[D_EMIT
]) {
753 printf("tp_emit before tpxxx_output tpcb %p, dutype 0x%x, datalen 0x%x\n",
754 tpcb
, dutype
, datalen
);
755 dump_buf(mtod(m
, void *), datalen
);
761 if (dutype
== DT_TPDU_type
) {
762 PStat(tpcb
, Nb_to_ll
) += (datalen
- m
->m_len
);
763 tpmeas(tpcb
->tp_lref
, TPtime_to_ll
, NULL
,
764 seq
, PStat(tpcb
, Nb_to_ll
),
765 (datalen
- m
->m_len
));
771 if (tp_traceflags
[D_EMIT
]) {
772 tptraceTPCB(TPPTtpduout
, dutype
, hdr
, hdr
->tpdu_li
+ 1, datalen
, 0);
776 if (argo_debug
[D_EMIT
]) {
777 printf("OUTPUT: tpcb %p, isop %p, so %p\n",
778 tpcb
, tpcb
->tp_npcb
, tpcb
->tp_sock
);
783 extern char tp_delay
;
786 if (tpcb
->tp_use_checksum
== 0) {
789 (void) iso_check_csum(m
, datalen
);
792 ASSERT(m
->m_len
> 0);
793 error
= (tpcb
->tp_nlproto
->nlp_output
) (m
, datalen
, tpcb
->tp_npcb
,
794 !tpcb
->tp_use_checksum
);
796 if (argo_debug
[D_EMIT
]) {
797 printf("OUTPUT: returned 0x%x\n", error
);
801 if (tp_traceflags
[D_EMIT
]) {
802 tptraceTPCB(TPPTmisc
,
803 "tp_emit nlproto->output netservice returns datalen",
804 tpcb
->tp_nlproto
->nlp_output
, tpcb
->tp_netservice
, error
, datalen
);
809 if (dutype
== AK_TPDU_type
)
810 tp_ctimeout(tpcb
, TM_sendack
, 1);
811 if (error
== E_CO_QFULL
) {
812 tp_quench((struct inpcb
*) tpcb
, PRC_QUENCH
);
819 * NAME: tp_error_emit()
820 * CALLED FROM: tp_input() when a DR or ER is to be issued in
821 * response to an input error.
822 * FUNCTION and ARGUMENTS:
823 * The error type is the first argument.
824 * The argument (sref) is the source reference on the bad incoming tpdu,
825 * and is used for a destination reference on the outgoing packet.
826 * (faddr) and (laddr) are the foreign and local addresses for this
828 * (erdata) is a ptr to the errant incoming tpdu, and is copied into the
829 * outgoing ER, if an ER is to be issued.
830 * (erlen) is the number of octets of the errant tpdu that we should
832 * (tpcb) is the pcb that describes the connection for which the bad tpdu
837 * E* from net layer datagram output routine
847 struct sockaddr_iso
*faddr
,
848 struct sockaddr_iso
*laddr
,
853 int (*dgout_routine
)(struct mbuf
*, ...))
862 if (tp_traceflags
[D_ERROR_EMIT
]) {
863 tptrace(TPPTmisc
, "tp_error_emit error sref tpcb erlen",
864 error
, sref
, tpcb
, erlen
);
868 if (argo_debug
[D_ERROR_EMIT
]) {
870 "tp_error_emit error 0x%x sref %lx tpcb %p erlen 0x%x chan %p\n",
871 error
, sref
, tpcb
, erlen
, cons_channel
);
875 MGET(m
, M_DONTWAIT
, TPMT_TPHDR
);
879 m
->m_len
= sizeof(struct tpdu
);
882 hdr
= mtod(m
, struct tpdu
*);
885 if (argo_debug
[D_ERROR_EMIT
]) {
886 printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
887 error
, error
& 0xff, (char) error
);
892 if (error
& TP_ERROR_SNDC
)
893 dutype
= DC_TPDU_type
;
894 else if (error
& 0x40) {
896 dutype
= ER_TPDU_type
;
898 dutype
= DR_TPDU_type
;
901 hdr
->tpdu_type
= dutype
;
909 hdr
->tpdu_DCdref
= htons(sref
);
910 hdr
->tpdu_DCsref
= tpcb
? htons(tpcb
->tp_lref
) : 0;
912 if (argo_debug
[D_ERROR_EMIT
]) {
913 printf("DC case:\n");
917 /* forget the add'l information variable part */
923 hdr
->tpdu_DRdref
= htons(sref
);
924 hdr
->tpdu_DRsref
= 0;
925 hdr
->tpdu_DRreason
= (char) error
;
927 if (argo_debug
[D_ERROR_EMIT
]) {
928 printf("DR case:\n");
932 /* forget the add'l information variable part */
938 hdr
->tpdu_ERreason
= (char) error
;
939 hdr
->tpdu_ERdref
= htons(sref
);
944 printf("TP PANIC: bad dutype 0x%x\n", dutype
);
948 if (tpcb
->tp_use_checksum
) {
949 ADDOPTION(TPP_checksum
, hdr
, 2, csum_offset
/* dummy argument */ );
950 csum_offset
= hdr
->tpdu_li
- 2;
953 ASSERT(hdr
->tpdu_li
< MLEN
);
956 if (dutype
== ER_TPDU_type
) {
957 /* copy the errant tpdu into another 'variable part' */
961 if (tp_traceflags
[D_ERROR_EMIT
]) {
962 tptrace(TPPTmisc
, "error_emit ER len tpduli", erlen
, hdr
->tpdu_li
,
967 if (argo_debug
[D_ERROR_EMIT
]) {
968 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen
, hdr
->tpdu_li
);
972 /* copy at most as many octets for which you have room */
973 if (erlen
+ hdr
->tpdu_li
+ 2 > TP_MAX_HEADER_LEN
)
974 erlen
= TP_MAX_HEADER_LEN
- hdr
->tpdu_li
- 2;
976 /* add the "invalid tpdu" parameter : required in class 0 */
977 P
= (char *) hdr
+ (int) (hdr
->tpdu_li
);
978 vbptr(P
)->tpv_code
= TPP_invalid_tpdu
; /* parameter code */
979 vbptr(P
)->tpv_len
= erlen
; /* parameter length */
980 m
->m_len
= hdr
->tpdu_li
+ 2; /* 1 for code, 1 for length */
983 * tp_input very likely handed us an mbuf chain w/ nothing in
984 * the first mbuf and the data following the empty mbuf
986 if (erdata
->m_len
== 0) {
987 erdata
= m_free(erdata
); /* returns the next mbuf
991 * copy only up to the bad octet
992 * (or max that will fit in a header
994 m
->m_next
= m_copy(erdata
, 0, erlen
);
995 hdr
->tpdu_li
+= erlen
+ 2;
999 if (argo_debug
[D_ERROR_EMIT
]) {
1000 printf("error_emit DR error %d tpduli %x\n", error
, hdr
->tpdu_li
);
1001 dump_buf((char *) hdr
, hdr
->tpdu_li
);
1004 m
->m_len
= hdr
->tpdu_li
;
1010 if (tp_traceflags
[D_ERROR_EMIT
]) {
1011 tptrace(TPPTtpduout
, 2, hdr
, hdr
->tpdu_li
+ 1, 0, 0);
1015 datalen
= m_datalen(m
);
1017 if (tpcb
->tp_use_checksum
) {
1019 if (tp_traceflags
[D_ERROR_EMIT
]) {
1020 tptrace(TPPTmisc
, "before gen csum datalen", datalen
, 0, 0, 0);
1024 if (argo_debug
[D_ERROR_EMIT
]) {
1025 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
1026 datalen
, csum_offset
);
1030 iso_gen_csum(m
, csum_offset
, datalen
);
1033 if (argo_debug
[D_ERROR_EMIT
]) {
1034 printf("OUTPUT: tpcb %p, isop %p, so %p\n",
1035 tpcb
, tpcb
->tp_npcb
, tpcb
->tp_sock
);
1040 printf("TP panic! cons channel %p but not cons configured\n",
1046 if (argo_debug
[D_ERROR_EMIT
]) {
1047 printf("tp_error_emit 1 sending DG: Laddr\n");
1048 dump_addr(sisotosa(laddr
));
1050 dump_addr(sisotosa(faddr
));
1053 return (*tpcb
->tp_nlproto
->nlp_dgoutput
) (m
, datalen
,
1056 /* no route */ (void *) 0, !tpcb
->tp_use_checksum
);
1057 } else if (dgout_routine
) {
1059 if (argo_debug
[D_ERROR_EMIT
]) {
1060 printf("tp_error_emit sending DG: Laddr\n");
1061 dump_addr(sisotosa(laddr
));
1063 dump_addr(sisotosa(faddr
));
1066 return (*dgout_routine
) (m
, datalen
, &laddr
->siso_addr
, &faddr
->siso_addr
,
1067 (void *) 0, /* nochecksum==false */ 0);
1070 if (argo_debug
[D_ERROR_EMIT
]) {
1071 printf("tp_error_emit DROPPING %p\n", m
);
1074 IncStat(ts_send_drop
);