]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_emit.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93
57 /***********************************************************
58 Copyright IBM Corporation 1987
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of IBM not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
70 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
78 ******************************************************************/
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
86 * This file contains tp_emit() and tp_error_emit(), which
87 * form TPDUs and hand them to ip.
88 * They take data in the form of mbuf chain, allocate mbufs as
89 * necessary for headers, and set the fields as appropriate from
90 * information found in the tpcb and net-level pcb.
92 * The worst thing about this code is adding the variable-length
93 * options on a machine that requires alignment for any memory access
94 * that isn't of size 1. See the macro ADDOPTION() below.
96 * We don't do any concatenation. (There's a kludge to test the
97 * basic mechanism of separation under the 'w' tpdebug option, that's all.)
100 #include <sys/param.h>
101 #include <sys/systm.h>
102 #include <sys/mbuf.h>
103 #include <sys/socket.h>
104 #include <sys/socketvar.h>
105 #include <sys/protosw.h>
106 #include <sys/errno.h>
107 #include <sys/time.h>
109 #include <netiso/iso.h>
110 #include <netiso/iso_pcb.h>
111 #include <netiso/argo_debug.h>
112 #include <netiso/tp_timer.h>
113 #include <netiso/tp_param.h>
114 #include <netiso/tp_stat.h>
115 #include <netiso/tp_pcb.h>
116 #include <netiso/tp_tpdu.h>
117 #include <netiso/tp_trace.h>
118 #include <netiso/tp_meas.h>
119 #include <netiso/tp_seq.h>
120 #include <netiso/iso_errno.h>
127 #include <netccitt/x25.h>
128 #include <netccitt/pk.h>
129 #include <netccitt/pk_var.h>
134 /* Here is a mighty kludge. The token ring misorders packets if you
135 * fire them at it too fast, and TP sans checksum is "too fast", so
136 * we have introduced a delay when checksumming isn't used.
138 char tp_delay
= 0x00; /* delay to keep token ring from blowing it */
143 * CALLED FROM: tp.trans and from tp_sbsend()
145 * FUNCTION and ARGUMENTS:
146 * Emits one tpdu of the type (dutype), of the format appropriate
147 * to the connection described by the pcb (tpcb), with sequence
148 * number (seq) (where appropriate), end-of-tsdu bit (eot) where
149 * appropriate, and with the data in the mbuf chain (data).
150 * For DR and ER tpdus, the argument (eot) is
151 * the reason for issuing the tpdu rather than an end-of-tsdu indicator.
156 * E* returned from net layer output rtn
162 * WE ASSUME that the tp header + all options will fit in ONE mbuf.
163 * If mbufs are 256 this will most likely be true, but if they are 128 it's
164 * possible that they won't.
165 * If you used every option on the CR + max. user data you'd overrun
166 * 112 but unless you used > 115 bytes for the security
167 * parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
168 * We don't support the security parameter, so this isn't a problem.
169 * If security is added, we ought to remove this assumption.
171 * We do not implement the flow control confirmation "element of procedure".
172 * A) it should not affect interoperability,
173 * B) it should not be necessary - the protocol will eventually
174 * straighten things out w/o FCC, as long as we don't have severely
175 * mismatched keepalive and inactivity timers, and
176 * C) it appears not to be REQUIRED, and
177 * D) it's incredibly grotesque, and no doubt will lengthen a few
179 * HOWEVER, we're thinking about putting it in anyway, for
180 * completeness, just like we did with ack subsequencing.
184 tp_emit(dutype
, tpcb
, seq
, eot
, data
)
191 register struct tpdu
*hdr
;
192 register struct mbuf
*m
;
200 * here we treat tpdu_li as if it DID include the li field, up until
201 * the end, at which time we subtract 1
202 * THis is because if we subtract 1 right away, we end up adding
203 * one every time we add an option.
207 "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
208 dutype
, tpcb
, eot
, seq
, data
);
211 if (dutype
== CR_TPDU
|| dutype
== CC_TPDU
) {
212 // m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
213 MALLOC(m
, struct mbuf
*, 256, M_MBUF
, M_NOWAIT
);
215 m
->m_type
= TPMT_TPHDR
;
216 mbstat
.m_mtypes
[TPMT_TPHDR
]++;
218 m
->m_nextpkt
= MNULL
;
219 m
->m_data
= m
->m_pktdat
;
220 m
->m_flags
= M_PKTHDR
;
223 MGETHDR(m
, M_DONTWAIT
, TPMT_TPHDR
);
225 m
->m_data
+= max_hdr
;
227 if(data
!= (struct mbuf
*)0)
232 m
->m_len
= sizeof(struct tpdu
);
235 hdr
= mtod(m
, struct tpdu
*);
236 bzero((caddr_t
)hdr
, sizeof(struct tpdu
));
241 hdr
->tpdu_type
= dutype
;
242 hdr
->tpdu_li
= tp_headersize(dutype
, tpcb
);
244 * class 0 doesn't use this for DT
245 * it'll just get overwritten below
247 hdr
->tpdu_dref
= htons(tpcb
->tp_fref
);
248 if( tpcb
->tp_use_checksum
||
249 (dutype
== CR_TPDU_type
&& (tpcb
->tp_class
& TP_CLASS_4
) )) {
250 csum_offset
= hdr
->tpdu_li
+ 2; /* DOESN'T include csum */
251 ADDOPTION(TPP_checksum
, hdr
, 2, eot
/* dummy arg */);
254 "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
255 csum_offset
, hdr
->tpdu_li
);
264 hdr
->tpdu_CRdref_0
= 0; /* must be zero */
266 if (!tpcb
->tp_cebit_off
) {
267 tpcb
->tp_win_recv
= tp_start_win
<< 8;
269 CONG_INIT_SAMPLE(tpcb
);
273 /* Case CC_TPDU_type used to be here */
277 hdr
->tpdu_CCsref
= htons(tpcb
->tp_lref
); /* same as CRsref */
279 if( tpcb
->tp_class
> TP_CLASS_1
) {
280 tpcb
->tp_sent_uwe
= tpcb
->tp_lcredit
-1;
281 tpcb
->tp_sent_rcvnxt
= 1;
282 tpcb
->tp_sent_lcdt
= tpcb
->tp_lcredit
;
283 hdr
->tpdu_cdt
= tpcb
->tp_lcredit
;
286 if (tpcb
->tp_netservice
== ISO_CONS
) {
287 struct isopcb
*isop
= (struct isopcb
*)tpcb
->tp_npcb
;
288 struct pklcd
*lcp
= (struct pklcd
*)(isop
->isop_chan
);
289 lcp
->lcd_flags
&= ~X25_DG_CIRCUIT
;
294 hdr
->tpdu_CCclass
= tp_mask_to_num(tpcb
->tp_class
);
295 hdr
->tpdu_CCoptions
=
296 (tpcb
->tp_xtd_format
? TPO_XTD_FMT
:0) |
297 (tpcb
->tp_use_efc
? TPO_USE_EFC
:0);
300 u_char perf_meas
= tpcb
->tp_perf_on
;
301 ADDOPTION(TPP_perf_meas
, hdr
, sizeof(perf_meas
), perf_meas
);
304 if( dutype
== CR_TPDU_type
) {
307 ASSERT( tpcb
->tp_lsuffixlen
> 0 );
308 ASSERT( tpcb
->tp_fsuffixlen
> 0 );
310 ADDOPTION(TPP_calling_sufx
, hdr
,
311 tpcb
->tp_lsuffixlen
, tpcb
->tp_lsuffix
[0]);
312 ADDOPTION(TPP_called_sufx
, hdr
,
313 tpcb
->tp_fsuffixlen
, tpcb
->tp_fsuffix
[0]);
318 ADDOPTION(TPP_tpdu_size
, hdr
,
319 sizeof(tpcb
->tp_tpdusize
), tpcb
->tp_tpdusize
);
321 if (tpcb
->tp_class
!= TP_CLASS_0
) {
322 short millisec
= 500*(tpcb
->tp_sendack_ticks
);
324 millisec
= htons(millisec
);
325 ADDOPTION(TPP_acktime
, hdr
, sizeof(short), millisec
);
327 x
= (tpcb
->tp_use_nxpd
? TPAO_USE_NXPD
: 0)
328 | (tpcb
->tp_use_rcc
? TPAO_USE_RCC
: 0)
329 | (tpcb
->tp_use_checksum
?0: TPAO_NO_CSUM
)
330 | (tpcb
->tp_xpd_service
? TPAO_USE_TXPD
: 0);
331 ADDOPTION(TPP_addl_opt
, hdr
, 1, x
);
333 if ((tpcb
->tp_l_tpdusize
^ (1 << tpcb
->tp_tpdusize
)) != 0) {
334 u_short size_s
= tpcb
->tp_l_tpdusize
>> 7;
335 u_char size_c
= size_s
;
336 ASSERT(tpcb
->tp_l_tpdusize
< 65536 * 128);
337 if (dutype
== CR_TPDU_type
)
338 tpcb
->tp_ptpdusize
= size_s
;
340 ADDOPTION(TPP_ptpdu_size
, hdr
, 1, size_c
);
342 size_s
= htons(size_s
);
343 ADDOPTION(TPP_ptpdu_size
, hdr
, 2, size_s
);
348 if( (dutype
== CR_TPDU_type
) && (tpcb
->tp_class
!= TP_CLASS_0
)){
350 ASSERT( 1 == sizeof(tpcb
->tp_vers
) );
351 ADDOPTION(TPP_vers
, hdr
, 1, tpcb
->tp_vers
);
353 /* for each alt protocol class x,
355 * option = concat(option, x);
356 * Well, for now we only have TP0 for an
357 * alternative so... this is easy.
359 * HOWEVER... There should be NO alt protocol
360 * class over CLNS. Need to see if the route suggests
361 * CONS, and iff so add alt class.
364 ADDOPTION(TPP_alt_class
, hdr
, 1, x
);
367 if( hdr
->tpdu_li
> MLEN
)
368 panic("tp_emit CR/CC");
373 if( hdr
->tpdu_DRdref
== 0 ) {
374 /* don't issue the DR */
378 hdr
->tpdu_DRsref
= htons(tpcb
->tp_lref
);
379 hdr
->tpdu_DRreason
= (u_char
)eot
; /* WHICH BYTE OF THIS??? */
381 /* forget the add'l information variable part */
385 case DC_TPDU_type
: /* not used in class 0 */
386 ASSERT( tpcb
->tp_class
!= TP_CLASS_0
);
387 hdr
->tpdu_DCsref
= htons(tpcb
->tp_lref
);
389 data
= (struct mbuf
*)0;
393 case XAK_TPDU_type
: /* xak not used in class 0 */
394 ASSERT( tpcb
->tp_class
!= TP_CLASS_0
); /* fall through */
398 tptraceTPCB(TPPTXack
, seq
, 0, 0, 0, 0);
400 data
= (struct mbuf
*)0;
401 if (tpcb
->tp_xtd_format
) {
403 union seq_type seqeotX
;
407 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
409 hdr
->tpdu_XAKseqX
= seq
;
410 #endif /* BYTE_ORDER */
412 hdr
->tpdu_XAKseq
= seq
;
414 IncStat(ts_XAK_sent
);
415 IncPStat(tpcb
, tps_XAK_sent
);
418 case XPD_TPDU_type
: /* xpd not used in class 0 */
419 ASSERT( tpcb
->tp_class
!= TP_CLASS_0
); /* fall through */
421 if (tpcb
->tp_xtd_format
) {
423 union seq_type seqeotX
;
427 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
429 hdr
->tpdu_XPDseqX
= seq
;
430 hdr
->tpdu_XPDeotX
= 1; /* always 1 for XPD tpdu */
431 #endif /* BYTE_ORDER */
433 hdr
->tpdu_XPDseq
= seq
;
434 hdr
->tpdu_XPDeot
= 1; /* always 1 for XPD tpdu */
436 IncStat(ts_XPD_sent
);
437 IncPStat(tpcb
, tps_XPD_sent
);
439 /* kludge to test the input size checking */
440 IFDEBUG(D_SIZE_CHECK
)
441 /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
442 printf("Sending too much data on XPD: 18 bytes\n");
451 tptraceTPCB(TPPTmisc
, "emit DT: eot seq tpdu_li", eot
, seq
,
454 if (tpcb
->tp_xtd_format
) {
456 union seq_type seqeotX
;
460 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
462 hdr
->tpdu_DTseqX
= seq
;
463 hdr
->tpdu_DTeotX
= eot
;
464 #endif /* BYTE_ORDER */
465 } else if (tpcb
->tp_class
== TP_CLASS_0
) {
467 printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m
, hdr
);
468 dump_buf( hdr
, hdr
->tpdu_li
+ 1 );
470 ((struct tp0du
*)hdr
)->tp0du_eot
= eot
;
471 ((struct tp0du
*)hdr
)->tp0du_mbz
= 0;
473 printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m
, hdr
);
474 dump_buf( hdr
, hdr
->tpdu_li
+ 1 );
477 hdr
->tpdu_DTseq
= seq
;
478 hdr
->tpdu_DTeot
= eot
;
481 IncStat(ts_EOT_sent
);
484 IncPStat(tpcb
, tps_DT_sent
);
487 case AK_TPDU_type
:/* ak not used in class 0 */
488 ASSERT( tpcb
->tp_class
!= TP_CLASS_0
);
489 data
= (struct mbuf
*)0;
490 olduwe
= tpcb
->tp_sent_uwe
;
492 if (seq
!= tpcb
->tp_sent_rcvnxt
|| tpcb
->tp_rsycnt
== 0) {
493 LOCAL_CREDIT( tpcb
);
495 SEQ(tpcb
,tpcb
->tp_rcvnxt
+ tpcb
->tp_lcredit
-1);
496 tpcb
->tp_sent_lcdt
= tpcb
->tp_lcredit
;
502 /* occasionally fake a reneging so
503 you can test subsequencing */
505 tpcb
->tp_reneged
= 1;
509 /* Are we about to reneg on credit?
510 * When might we do so?
511 * a) when using optimistic credit (which we no longer do).
512 * b) when drain() gets implemented (not in the plans).
513 * c) when D_RENEG is on.
514 * d) when DEC BIT response is implemented.
515 * (not- when we do this, we'll need to implement flow control
518 if( SEQ_LT(tpcb
, tpcb
->tp_sent_uwe
, olduwe
) ) {
519 tpcb
->tp_reneged
= 1;
520 IncStat(ts_lcdt_reduced
);
522 tptraceTPCB(TPPTmisc
,
523 "RENEG: olduwe newuwe lcredit rcvnxt",
525 tpcb
->tp_sent_uwe
, tpcb
->tp_lcredit
,
530 /* new lwe is less than old uwe means we're
531 * acking before we received a whole window full
533 if( SEQ_LT( tpcb
, tpcb
->tp_rcvnxt
, olduwe
) ) {
534 /* tmp1 = number of pkts fewer than the full window */
536 (int) SEQ_SUB( tpcb
, olduwe
, tpcb
->tp_rcvnxt
);
540 IncPStat( tpcb
, tps_ack_early
[tmp1
] );
542 /* tmp1 = amt of new cdt we're advertising */
543 tmp1
= SEQ_SUB( tpcb
, seq
, tpcb
->tp_sent_rcvnxt
);
544 if(tmp1
> TP_PM_MAX
)
548 tps_cdt_acked
[ tmp1
]
549 [ ((tpcb
->tp_lcredit
> TP_PM_MAX
)?
550 TP_PM_MAX
:tpcb
->tp_lcredit
) ] );
556 tptraceTPCB(TPPTack
, seq
, tpcb
->tp_lcredit
, tpcb
->tp_sent_uwe
,
557 tpcb
->tp_r_subseq
, 0);
559 if (tpcb
->tp_xtd_format
) {
561 union seq_type seqeotX
;
565 hdr
->tpdu_seqeotX
= htonl(seqeotX
.s_seqeot
);
566 hdr
->tpdu_AKcdtX
= htons(tpcb
->tp_lcredit
);
569 hdr
->tpdu_AKseqX
= seq
;
570 hdr
->tpdu_AKcdtX
= tpcb
->tp_lcredit
;
571 #endif /* BYTE_ORDER */
573 hdr
->tpdu_AKseq
= seq
;
574 hdr
->tpdu_AKcdt
= tpcb
->tp_lcredit
;
576 if ((tpcb
->tp_class
== TP_CLASS_4
) &&
577 (tpcb
->tp_reneged
|| acking_ooo
)) {
579 * Ack subsequence parameter req'd if WE reneged on
580 * credit offered. (ISO 8073, 12.2.3.8.2, p. 74)
583 printf("Adding subseq 0x%x\n", tpcb
->tp_s_subseq
);
587 * add tmp subseq and do a htons on it.
589 ADDOPTION(TPP_subseq
, hdr
,
590 sizeof(tpcb
->tp_s_subseq
), tpcb
->tp_s_subseq
);
592 tpcb
->tp_s_subseq
= 0;
594 if ( tpcb
->tp_sendfcc
|| eot
) /* overloaded to mean SEND FCC */ {
596 * Rules for sending FCC ("should" send when) :
597 * %a) received an ack from peer with NO NEWS whatsoever,
598 * and it did not contain an FCC
599 * b) received an ack from peer that opens its closed window.
600 * c) received an ack from peer after it reneged on its
601 * offered credit, AND this ack raises UWE but LWE is same
602 * and below UWE at time of reneging (reduction)
603 * Now, ISO 8073 12.2.3.8.3 says
604 * that a retransmitted AK shall not contain the FCC
605 * parameter. Now, how the hell you tell the difference
606 * between a retransmitted ack and an ack that's sent in
607 * response to a received ack, I don't know, because without
608 * any local activity, and w/o any received DTs, they
609 * will contain exactly the same credit/seq# information.
610 * Anyway, given that the "retransmission of acks"
611 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
612 * don't do it (although the peer can't tell that), we
613 * ignore this last rule.
615 * We send FCC for reasons a) and b) only.
616 * To add reason c) would require a ridiculous amount of state.
619 u_short bogus
[4]; /* lwe(32), subseq(16), cdt(16) */
621 u_short subseq
, fcredit
;
623 tpcb
->tp_sendfcc
= 0;
625 lwe
= (SeqNum
) htonl(tpcb
->tp_snduna
);
626 subseq
= htons(tpcb
->tp_r_subseq
);
627 fcredit
= htons(tpcb
->tp_fcredit
);
629 bcopy((caddr_t
) &lwe
, (caddr_t
)&bogus
[0], sizeof(SeqNum
));
630 bcopy((caddr_t
) &subseq
, (caddr_t
)&bogus
[2], sizeof(u_short
));
631 bcopy((caddr_t
) &fcredit
, (caddr_t
)&bogus
[3], sizeof(u_short
));
634 tptraceTPCB(TPPTmisc
,
635 "emit w/FCC: snduna r_subseq fcredit",
636 tpcb
->tp_snduna
, tpcb
->tp_r_subseq
,
637 tpcb
->tp_fcredit
, 0);
641 printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
643 hdr
, sizeof(bogus
), bogus
[0]);
645 ADDOPTION(TPP_flow_cntl_conf
, hdr
, sizeof(bogus
), bogus
[0]);
647 printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
650 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
651 csum_offset
, hdr
->tpdu_li
);
655 tpcb
->tp_reneged
= 0;
656 tpcb
->tp_sent_rcvnxt
= seq
;
657 if (tpcb
->tp_fcredit
== 0) {
658 int timo
= tpcb
->tp_keepalive_ticks
;
659 if (tpcb
->tp_rxtshift
< TP_MAXRXTSHIFT
)
661 timo
= min(timo
, ((int)tpcb
->tp_dt_ticks
) << tpcb
->tp_rxtshift
);
662 tp_ctimeout(tpcb
, TM_sendack
, timo
);
664 tp_ctimeout(tpcb
, TM_sendack
, tpcb
->tp_keepalive_ticks
);
666 IncPStat(tpcb
, tps_AK_sent
);
669 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
670 csum_offset
, hdr
->tpdu_li
);
675 hdr
->tpdu_ERreason
= eot
;
678 data
= (struct mbuf
*)0;
684 ASSERT( ((int)hdr
->tpdu_li
> 0) && ((int)hdr
->tpdu_li
< MLEN
) );
688 ASSERT( hdr
->tpdu_li
< MLEN
); /* leave this in */
689 ASSERT( hdr
->tpdu_li
!= 0 ); /* leave this in */
691 m
->m_len
= hdr
->tpdu_li
;
692 hdr
->tpdu_li
--; /* doesn't include the li field */
694 datalen
= m_datalen( m
); /* total len */
696 ASSERT( datalen
<= tpcb
->tp_l_tpdusize
); /* may become a problem
697 when CLNP is used; leave in here for the time being */
700 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
701 csum_offset
, hdr
->tpdu_li
);
703 if( datalen
> tpcb
->tp_l_tpdusize
) {
704 printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
705 datalen
, tpcb
->tp_l_tpdusize
);
709 "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
710 m
->m_len
, csum_offset
, datalen
);
712 if( tpcb
->tp_use_checksum
||
713 (dutype
== CR_TPDU_type
&& (tpcb
->tp_class
& TP_CLASS_4
)) ) {
714 iso_gen_csum(m
, csum_offset
, datalen
);
718 printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
719 tpcb
, dutype
, datalen
);
720 dump_buf(mtod(m
, caddr_t
), datalen
);
724 if( dutype
== DT_TPDU_type
) {
725 PStat(tpcb
, Nb_to_ll
) += (datalen
- m
->m_len
);
726 tpmeas( tpcb
->tp_lref
, TPtime_to_ll
, (struct timeval
*)0,
727 seq
, PStat(tpcb
, Nb_to_ll
), (datalen
- m
->m_len
));
732 tptraceTPCB(TPPTtpduout
, dutype
, hdr
, hdr
->tpdu_li
+1, datalen
, 0);
735 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
736 tpcb
, tpcb
->tp_npcb
, tpcb
->tp_sock
);
739 { extern char tp_delay
;
742 if( tpcb
->tp_use_checksum
== 0 ) {
743 register u_int i
= tp_delay
;
745 (void) iso_check_csum(m
, datalen
);
748 ASSERT( m
->m_len
> 0 );
749 error
= (tpcb
->tp_nlproto
->nlp_output
)(tpcb
->tp_npcb
, m
, datalen
,
750 !tpcb
->tp_use_checksum
);
752 printf("OUTPUT: returned 0x%x\n", error
);
755 tptraceTPCB(TPPTmisc
,
756 "tp_emit nlproto->output netservice returns datalen",
757 tpcb
->tp_nlproto
->nlp_output
, tpcb
->tp_netservice
, error
, datalen
);
761 if (dutype
== AK_TPDU_type
)
762 tp_ctimeout(tpcb
, TM_sendack
, 1);
763 if (error
== E_CO_QFULL
) {
764 tp_quench(tpcb
, PRC_QUENCH
);
771 * NAME: tp_error_emit()
772 * CALLED FROM: tp_input() when a DR or ER is to be issued in
773 * response to an input error.
774 * FUNCTION and ARGUMENTS:
775 * The error type is the first argument.
776 * The argument (sref) is the source reference on the bad incoming tpdu,
777 * and is used for a destination reference on the outgoing packet.
778 * (faddr) and (laddr) are the foreign and local addresses for this
780 * (erdata) is a ptr to the errant incoming tpdu, and is copied into the
781 * outgoing ER, if an ER is to be issued.
782 * (erlen) is the number of octets of the errant tpdu that we should
784 * (tpcb) is the pcb that describes the connection for which the bad tpdu
789 * E* from net layer datagram output routine
796 tp_error_emit(error
, sref
, faddr
, laddr
, erdata
, erlen
, tpcb
, cons_channel
,
800 struct sockaddr_iso
*faddr
, *laddr
;
804 caddr_t cons_channel
;
805 int (*dgout_routine
)();
809 register struct tpdu
*hdr
;
810 register struct mbuf
*m
;
813 IFTRACE(D_ERROR_EMIT
)
814 tptrace(TPPTmisc
, "tp_error_emit error sref tpcb erlen",
815 error
, sref
, tpcb
, erlen
);
817 IFDEBUG(D_ERROR_EMIT
)
819 "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
820 error
, sref
, tpcb
, erlen
, cons_channel
);
823 MGET(m
, M_DONTWAIT
, TPMT_TPHDR
);
827 m
->m_len
= sizeof(struct tpdu
);
830 hdr
= mtod(m
, struct tpdu
*);
832 IFDEBUG(D_ERROR_EMIT
)
833 printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
834 error
, error
&0xff, (char)error
);
838 if (error
& TP_ERROR_SNDC
)
839 dutype
= DC_TPDU_type
;
840 else if (error
& 0x40) {
842 dutype
= ER_TPDU_type
;
844 dutype
= DR_TPDU_type
;
847 hdr
->tpdu_type
= dutype
;
855 hdr
->tpdu_DCdref
= htons(sref
);
856 hdr
->tpdu_DCsref
= tpcb
? htons(tpcb
->tp_lref
) : 0;
857 IFDEBUG(D_ERROR_EMIT
)
858 printf("DC case:\n");
861 /* forget the add'l information variable part */
867 hdr
->tpdu_DRdref
= htons(sref
);
868 hdr
->tpdu_DRsref
= 0;
869 hdr
->tpdu_DRreason
= (char)error
;
870 IFDEBUG(D_ERROR_EMIT
)
871 printf("DR case:\n");
874 /* forget the add'l information variable part */
880 hdr
->tpdu_ERreason
= (char)error
;
881 hdr
->tpdu_ERdref
= htons(sref
);
886 printf("TP PANIC: bad dutype 0x%x\n", dutype
);
890 if( tpcb
->tp_use_checksum
) {
891 ADDOPTION(TPP_checksum
, hdr
, 2, csum_offset
/* dummy argument */);
892 csum_offset
= hdr
->tpdu_li
- 2;
895 ASSERT( hdr
->tpdu_li
< MLEN
);
897 if (dutype
== ER_TPDU_type
) {
898 /* copy the errant tpdu into another 'variable part' */
901 IFTRACE(D_ERROR_EMIT
)
902 tptrace(TPPTmisc
, "error_emit ER len tpduli", erlen
, hdr
->tpdu_li
,
905 IFDEBUG(D_ERROR_EMIT
)
906 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen
, hdr
->tpdu_li
);
909 /* copy at most as many octets for which you have room */
910 if (erlen
+ hdr
->tpdu_li
+ 2 > TP_MAX_HEADER_LEN
)
911 erlen
= TP_MAX_HEADER_LEN
- hdr
->tpdu_li
- 2;
913 /* add the "invalid tpdu" parameter : required in class 0 */
914 P
= (caddr_t
)hdr
+ (int)(hdr
->tpdu_li
);
915 vbptr(P
)->tpv_code
= TPP_invalid_tpdu
; /* parameter code */
916 vbptr(P
)->tpv_len
= erlen
; /* parameter length */
917 m
->m_len
= hdr
->tpdu_li
+ 2; /* 1 for code, 1 for length */
919 /* tp_input very likely handed us an mbuf chain w/ nothing in
920 * the first mbuf and the data following the empty mbuf
922 if(erdata
->m_len
== 0) {
923 erdata
= m_free(erdata
); /* returns the next mbuf on the chain */
926 * copy only up to the bad octet
927 * (or max that will fit in a header
929 m
->m_next
= m_copy(erdata
, 0, erlen
);
930 hdr
->tpdu_li
+= erlen
+ 2;
933 IFDEBUG(D_ERROR_EMIT
)
934 printf("error_emit DR error tpduli 0x%x\n", error
, hdr
->tpdu_li
);
935 dump_buf( (char *)hdr
, hdr
->tpdu_li
);
937 m
->m_len
= hdr
->tpdu_li
;
942 IFTRACE(D_ERROR_EMIT
)
943 tptrace(TPPTtpduout
, 2, hdr
, hdr
->tpdu_li
+1, 0, 0);
946 datalen
= m_datalen( m
);
948 if( tpcb
->tp_use_checksum
) {
949 IFTRACE(D_ERROR_EMIT
)
950 tptrace(TPPTmisc
, "before gen csum datalen", datalen
,0,0,0);
952 IFDEBUG(D_ERROR_EMIT
)
953 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
954 datalen
, csum_offset
);
957 iso_gen_csum(m
, csum_offset
, datalen
);
960 IFDEBUG(D_ERROR_EMIT
)
961 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
962 tpcb
, tpcb
->tp_npcb
, tpcb
->tp_sock
);
967 struct pklcd
*lcp
= (struct pklcd
*)cons_channel
;
968 struct isopcb
*isop
= (struct isopcb
*)lcp
->lcd_upnext
;
970 tpcons_dg_output(cons_channel
, m
, datalen
);
971 /* was if (tpcb == 0) iso_pcbdetach(isop); */
972 /* but other side may want to try again over same VC,
973 so, we'll depend on him closing it, but in case it gets forgotten
974 we'll mark it for garbage collection */
975 lcp
->lcd_flags
|= X25_DG_CIRCUIT
;
976 IFDEBUG(D_ERROR_EMIT
)
977 printf("OUTPUT: dutype 0x%x channel 0x%x\n",
978 dutype
, cons_channel
);
981 printf("TP panic! cons channel 0x%x but not cons configured\n",
986 IFDEBUG(D_ERROR_EMIT
)
987 printf("tp_error_emit 1 sending DG: Laddr\n");
988 dump_addr((struct sockaddr
*)laddr
);
990 dump_addr((struct sockaddr
*)faddr
);
992 return (tpcb
->tp_nlproto
->nlp_dgoutput
)(
996 /* no route */ (caddr_t
)0, !tpcb
->tp_use_checksum
);
997 } else if (dgout_routine
) {
998 IFDEBUG(D_ERROR_EMIT
)
999 printf("tp_error_emit sending DG: Laddr\n");
1000 dump_addr((struct sockaddr
*)laddr
);
1002 dump_addr((struct sockaddr
*)faddr
);
1004 return (*dgout_routine
)( &laddr
->siso_addr
, &faddr
->siso_addr
,
1005 m
, datalen
, /* no route */
1006 (caddr_t
)0, /* nochecksum==false */0);
1008 IFDEBUG(D_ERROR_EMIT
)
1009 printf("tp_error_emit DROPPING \n", m
);
1011 IncStat(ts_send_drop
);