No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netiso / tp_emit.c
blob3215ea44dfab17aa4a20a3129eb47626007839c0
1 /* $NetBSD: tp_emit.c,v 1.29 2009/03/18 17:06:53 cegger Exp $ */
3 /*-
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
9 * are met:
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
29 * SUCH DAMAGE.
31 * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93
34 /***********************************************************
35 Copyright IBM Corporation 1987
37 All Rights Reserved
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
53 SOFTWARE.
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 $");
77 #include "opt_iso.h"
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/mbuf.h>
82 #include <sys/socket.h>
83 #include <sys/socketvar.h>
84 #include <sys/protosw.h>
85 #include <sys/errno.h>
86 #include <sys/time.h>
88 #include <net/if.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 */
113 * NAME: tp_emit()
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.
125 * RETURNS:
126 * 0 OK
127 * ENOBUFS
128 * E* returned from net layer output rtn
130 * SIDE EFFECTS:
132 * NOTES:
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
150 * critical paths.
151 * HOWEVER, we're thinking about putting it in anyway, for
152 * completeness, just like we did with ack subsequencing.
156 tp_emit(
157 int dutype,
158 struct tp_pcb *tpcb,
159 SeqNum seq,
160 u_int eot,
161 struct mbuf *data)
163 struct tpdu *hdr;
164 struct mbuf *m;
165 int csum_offset = 0;
166 int datalen = 0;
167 int error = 0;
168 SeqNum olduwe;
169 int acking_ooo;
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
175 * option.
177 #ifdef ARGO_DEBUG
178 if (argo_debug[D_EMIT]) {
179 printf(
180 "tp_emit dutype 0x%x, tpcb %p, eot 0x%x, seq 0x%x, data %p",
181 dutype, tpcb, eot, seq, data);
183 #endif
185 if (dutype == CR_TPDU || dutype == CC_TPDU) {
186 m = (struct mbuf *) malloc((u_long) 256, M_MBUF, M_DONTWAIT);
187 if (m) {
188 m->m_type = TPMT_TPHDR;
189 mbstat.m_mtypes[TPMT_TPHDR]++;
190 m->m_next = NULL;
191 m->m_nextpkt = NULL;
192 m->m_data = m->m_pktdat;
193 m->m_flags = M_PKTHDR;
194 memset(&m->m_pkthdr, 0, sizeof(m->m_pkthdr));
196 } else {
197 MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
199 if (m == NULL) {
200 if (data != (struct mbuf *) 0)
201 m_freem(data);
202 error = ENOBUFS;
203 goto done;
205 m->m_data += max_hdr;
206 m->m_len = sizeof(struct tpdu);
207 m->m_nextpkt = NULL;
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 */ );
224 #ifdef ARGO_DEBUG
225 if (argo_debug[D_CHKSUM]) {
226 printf(
227 "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
228 csum_offset, hdr->tpdu_li);
230 #endif
233 * VARIABLE PARTS...
235 switch (dutype) {
237 case CR_TPDU_type:
238 hdr->tpdu_CRdref_0 = 0; /* must be zero */
239 case CC_TPDU_type:
240 if (!tpcb->tp_cebit_off) {
241 tpcb->tp_win_recv = tp_start_win << 8;
242 LOCAL_CREDIT(tpcb);
243 CONG_INIT_SAMPLE(tpcb);
244 } else
245 LOCAL_CREDIT(tpcb);
247 /* Case CC_TPDU_type used to be here */
249 u_char x;
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;
258 } else {
259 hdr->tpdu_cdt = 0;
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);
266 #ifdef TP_PERF_MEAS
267 if (DOPERF(tpcb)) {
268 u_char perf_meas = tpcb->tp_perf_on;
269 ADDOPTION(TPP_perf_meas, hdr,
270 sizeof(perf_meas), perf_meas);
272 #endif
274 if (dutype == CR_TPDU_type) {
275 IncStat(ts_CR_sent);
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]);
284 } else {
285 IncStat(ts_CC_sent);
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;
309 if (size_s < 256) {
310 ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
311 } else {
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.
333 x = 0;
334 ADDOPTION(TPP_alt_class, hdr, 1, x);
336 #if 0
337 if (hdr->tpdu_li > MLEN)
338 panic("tp_emit CR/CC");
339 #endif
341 break;
343 case DR_TPDU_type:
344 if (hdr->tpdu_DRdref == 0) {
345 /* don't issue the DR */
346 goto done;
348 hdr->tpdu_cdt = 0;
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 */
353 IncStat(ts_DR_sent);
354 break;
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);
359 hdr->tpdu_cdt = 0;
360 data = (struct mbuf *) 0;
361 IncStat(ts_DC_sent);
362 break;
364 case XAK_TPDU_type: /* xak not used in class 0 */
365 ASSERT(tpcb->tp_class != TP_CLASS_0); /* fall through */
366 hdr->tpdu_cdt = 0;
368 #ifdef TPPT
369 if (tp_traceflags[D_XPD]) {
370 tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
372 #endif
373 data = (struct mbuf *) 0;
374 if (tpcb->tp_xtd_format) {
375 #ifdef BYTE_ORDER
376 union seq_type seqeotX;
378 seqeotX.s_seq = seq;
379 seqeotX.s_eot = 1;
380 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
381 #else
382 hdr->tpdu_XAKseqX = seq;
383 #endif /* BYTE_ORDER */
384 } else {
385 hdr->tpdu_XAKseq = seq;
387 IncStat(ts_XAK_sent);
388 IncPStat(tpcb, tps_XAK_sent);
389 break;
391 case XPD_TPDU_type: /* xpd not used in class 0 */
392 ASSERT(tpcb->tp_class != TP_CLASS_0); /* fall through */
393 hdr->tpdu_cdt = 0;
394 if (tpcb->tp_xtd_format) {
395 #ifdef BYTE_ORDER
396 union seq_type seqeotX;
398 seqeotX.s_seq = seq;
399 seqeotX.s_eot = 1;
400 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
401 #else
402 hdr->tpdu_XPDseqX = seq;
403 hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
404 #endif /* BYTE_ORDER */
405 } else {
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 */
413 #ifdef ARGO_DEBUG
414 if (argo_debug[D_SIZE_CHECK]) {
415 #if 0
416 if (data->m_len <= 16 &&
417 data->m_off < (MLEN-18)) {
418 printf("Sending too much data on XPD: 18 bytes\n");
419 data->m_len = 18;
421 #endif
423 #endif
424 break;
426 case DT_TPDU_type:
427 hdr->tpdu_cdt = 0;
428 #ifdef TPPT
429 if (tp_traceflags[D_DATA]) {
430 tptraceTPCB(TPPTmisc,
431 "emit DT: eot seq tpdu_li", eot,
432 seq, hdr->tpdu_li, 0);
434 #endif
435 if (tpcb->tp_xtd_format) {
436 #ifdef BYTE_ORDER
437 union seq_type seqeotX;
439 seqeotX.s_seq = seq;
440 seqeotX.s_eot = eot;
441 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
442 #else
443 hdr->tpdu_DTseqX = seq;
444 hdr->tpdu_DTeotX = eot;
445 #endif /* BYTE_ORDER */
446 } else if (tpcb->tp_class == TP_CLASS_0) {
447 #ifdef ARGO_DEBUG
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);
452 #endif
453 ((struct tp0du *) hdr)->tp0du_eot = eot;
454 ((struct tp0du *) hdr)->tp0du_mbz = 0;
455 #ifdef ARGO_DEBUG
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);
460 #endif
461 } else {
462 hdr->tpdu_DTseq = seq;
463 hdr->tpdu_DTeot = eot;
465 if (eot) {
466 IncStat(ts_EOT_sent);
468 IncStat(ts_DT_sent);
469 IncPStat(tpcb, tps_DT_sent);
470 break;
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) {
478 LOCAL_CREDIT(tpcb);
479 tpcb->tp_sent_uwe =
480 SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_lcredit - 1);
481 tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
482 acking_ooo = 0;
483 } else
484 acking_ooo = 1;
486 #ifdef ARGO_DEBUG
487 if (argo_debug[D_RENEG]) {
489 * occasionally fake a reneging so you can test
490 * subsequencing
492 if (olduwe & 0x1) {
493 tpcb->tp_reneged = 1;
494 IncStat(ts_ldebug);
497 #endif
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
505 * confirmation)
507 if (SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe)) {
508 tpcb->tp_reneged = 1;
509 IncStat(ts_lcdt_reduced);
510 #ifdef TPPT
511 if (tp_traceflags[D_CREDIT]) {
512 tptraceTPCB(TPPTmisc,
513 "RENEG: olduwe newuwe lcredit rcvnxt",
514 olduwe,
515 tpcb->tp_sent_uwe, tpcb->tp_lcredit,
516 tpcb->tp_rcvnxt);
518 #endif
520 #ifdef TP_PERF_MEAS
521 if (DOPERF(tpcb)) {
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
529 * the full window
531 int tmp1 =
532 (int) SEQ_SUB(tpcb, olduwe,
533 tpcb->tp_rcvnxt);
535 if (tmp1 > TP_PM_MAX)
536 tmp1 = TP_PM_MAX;
537 IncPStat(tpcb, tps_ack_early[tmp1]);
540 * tmp1 = amt of new cdt we're
541 * advertising
543 tmp1 = SEQ_SUB(tpcb, seq,
544 tpcb->tp_sent_rcvnxt);
545 if (tmp1 > TP_PM_MAX)
546 tmp1 = TP_PM_MAX;
548 IncPStat(tpcb,
549 tps_cdt_acked[tmp1]
550 [((tpcb->tp_lcredit >
551 TP_PM_MAX) ?
552 TP_PM_MAX :
553 tpcb->tp_lcredit)]);
557 #endif
559 #ifdef TPPT
560 if (tp_traceflags[D_ACKSEND]) {
561 tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit,
562 tpcb->tp_sent_uwe,
563 tpcb->tp_r_subseq, 0);
565 #endif
566 if (tpcb->tp_xtd_format) {
567 #ifdef BYTE_ORDER
568 union seq_type seqeotX;
570 seqeotX.s_seq = seq;
571 seqeotX.s_eot = 0;
572 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
573 hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
574 #else
575 hdr->tpdu_cdt = 0;
576 hdr->tpdu_AKseqX = seq;
577 hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
578 #endif /* BYTE_ORDER */
579 } else {
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,
588 * 12.2.3.8.2, p. 74)
590 #ifdef ARGO_DEBUG
591 if (argo_debug[D_RENEG]) {
592 printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
594 #endif
595 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);
601 } else
602 tpcb->tp_s_subseq = 0;
604 if (tpcb->tp_sendfcc || eot) { /* overloaded to mean
605 * SEND FCC */
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
632 * amount of state.
635 u_short bogus[4]; /* lwe(32), subseq(16),
636 * cdt(16) */
637 SeqNum lwe;
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));
650 #ifdef TPPT
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);
657 #endif
659 #ifdef ARGO_DEBUG
660 if (argo_debug[D_ACKSEND]) {
661 printf("Calling ADDOPTION 0x%x, %p, 0x%lx,0x%x\n",
662 TPP_flow_cntl_conf,
663 hdr, (unsigned long)sizeof(bogus), bogus[0]);
665 #endif
666 ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
667 #ifdef ARGO_DEBUG
668 if (argo_debug[D_ACKSEND]) {
669 printf("after ADDOPTION hdr %p hdr->tpdu_li 0x%x\n",
670 hdr, hdr->tpdu_li);
671 printf(
672 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
673 csum_offset, hdr->tpdu_li);
675 #endif
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)
683 tpcb->tp_rxtshift++;
684 timo = min(timo, ((int) tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
685 tp_ctimeout(tpcb, TM_sendack, timo);
686 } else
687 tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
688 IncStat(ts_AK_sent);
689 IncPStat(tpcb, tps_AK_sent);
690 #ifdef ARGO_DEBUG
691 if (argo_debug[D_ACKSEND]) {
692 printf(
693 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
694 csum_offset, hdr->tpdu_li);
696 #endif
697 break;
699 case ER_TPDU_type:
700 hdr->tpdu_ERreason = eot;
701 hdr->tpdu_cdt = 0;
702 /* no user data */
703 data = (struct mbuf *) 0;
704 IncStat(ts_ER_sent);
705 break;
709 ASSERT((int) hdr->tpdu_li != 0);
710 #if 0
711 ASSERT((int) hdr->tpdu_li < MLEN);
712 #endif
714 m->m_next = data;
716 #if 0
717 ASSERT(hdr->tpdu_li < MLEN); /* leave this in */
718 #endif
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 */
729 #ifdef ARGO_DEBUG
730 if (argo_debug[D_ACKSEND]) {
731 printf(
732 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
733 csum_offset, hdr->tpdu_li);
735 #endif
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);
740 #ifdef ARGO_DEBUG
741 if (argo_debug[D_EMIT]) {
742 printf(
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);
746 #endif
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);
751 #ifdef ARGO_DEBUG
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);
757 #endif
759 #ifdef TP_PERF_MEAS
760 if (DOPERF(tpcb)) {
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));
768 #endif
770 #ifdef TPPT
771 if (tp_traceflags[D_EMIT]) {
772 tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li + 1, datalen, 0);
774 #endif
775 #ifdef ARGO_DEBUG
776 if (argo_debug[D_EMIT]) {
777 printf("OUTPUT: tpcb %p, isop %p, so %p\n",
778 tpcb, tpcb->tp_npcb, tpcb->tp_sock);
780 #endif
783 extern char tp_delay;
785 if (tp_delay)
786 if (tpcb->tp_use_checksum == 0) {
787 u_int i = tp_delay;
788 for (; i != 0; i--)
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);
795 #ifdef ARGO_DEBUG
796 if (argo_debug[D_EMIT]) {
797 printf("OUTPUT: returned 0x%x\n", error);
799 #endif
800 #ifdef TPPT
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);
806 #endif
807 done:
808 if (error) {
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);
813 return 0;
816 return error;
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
827 * connection.
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
831 * try to copy.
832 * (tpcb) is the pcb that describes the connection for which the bad tpdu
833 * arrived.
834 * RETURN VALUES:
835 * 0 OK
836 * ENOBUFS
837 * E* from net layer datagram output routine
838 * SIDE EFFECTS:
840 * NOTES:
844 tp_error_emit(
845 int error,
846 u_long sref,
847 struct sockaddr_iso *faddr,
848 struct sockaddr_iso *laddr,
849 struct mbuf *erdata,
850 int erlen,
851 struct tp_pcb *tpcb,
852 void * cons_channel,
853 int (*dgout_routine)(struct mbuf *, ...))
855 int dutype;
856 int datalen = 0;
857 struct tpdu *hdr;
858 struct mbuf *m;
859 int csum_offset;
861 #ifdef TPPT
862 if (tp_traceflags[D_ERROR_EMIT]) {
863 tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
864 error, sref, tpcb, erlen);
866 #endif
867 #ifdef ARGO_DEBUG
868 if (argo_debug[D_ERROR_EMIT]) {
869 printf(
870 "tp_error_emit error 0x%x sref %lx tpcb %p erlen 0x%x chan %p\n",
871 error, sref, tpcb, erlen, cons_channel);
873 #endif
875 MGET(m, M_DONTWAIT, TPMT_TPHDR);
876 if (m == NULL) {
877 return ENOBUFS;
879 m->m_len = sizeof(struct tpdu);
880 m->m_nextpkt = NULL;
882 hdr = mtod(m, struct tpdu *);
884 #ifdef ARGO_DEBUG
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);
889 #endif
892 if (error & TP_ERROR_SNDC)
893 dutype = DC_TPDU_type;
894 else if (error & 0x40) {
895 error &= ~0x40;
896 dutype = ER_TPDU_type;
897 } else
898 dutype = DR_TPDU_type;
899 error &= 0xff;
901 hdr->tpdu_type = dutype;
902 hdr->tpdu_cdt = 0;
904 switch (dutype) {
906 case DC_TPDU_type:
907 IncStat(ts_DC_sent);
908 hdr->tpdu_li = 6;
909 hdr->tpdu_DCdref = htons(sref);
910 hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
911 #ifdef ARGO_DEBUG
912 if (argo_debug[D_ERROR_EMIT]) {
913 printf("DC case:\n");
914 dump_buf(hdr, 6);
916 #endif
917 /* forget the add'l information variable part */
918 break;
920 case DR_TPDU_type:
921 IncStat(ts_DR_sent);
922 hdr->tpdu_li = 7;
923 hdr->tpdu_DRdref = htons(sref);
924 hdr->tpdu_DRsref = 0;
925 hdr->tpdu_DRreason = (char) error;
926 #ifdef ARGO_DEBUG
927 if (argo_debug[D_ERROR_EMIT]) {
928 printf("DR case:\n");
929 dump_buf(hdr, 7);
931 #endif
932 /* forget the add'l information variable part */
933 break;
935 case ER_TPDU_type:
936 IncStat(ts_ER_sent);
937 hdr->tpdu_li = 5;
938 hdr->tpdu_ERreason = (char) error;
939 hdr->tpdu_ERdref = htons(sref);
940 break;
942 default:
943 ASSERT(0);
944 printf("TP PANIC: bad dutype 0x%x\n", dutype);
947 if (tpcb)
948 if (tpcb->tp_use_checksum) {
949 ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */ );
950 csum_offset = hdr->tpdu_li - 2;
952 #if 0
953 ASSERT(hdr->tpdu_li < MLEN);
954 #endif
956 if (dutype == ER_TPDU_type) {
957 /* copy the errant tpdu into another 'variable part' */
958 void *P;
960 #ifdef TPPT
961 if (tp_traceflags[D_ERROR_EMIT]) {
962 tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
963 0, 0);
965 #endif
966 #ifdef ARGO_DEBUG
967 if (argo_debug[D_ERROR_EMIT]) {
968 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
970 #endif
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
988 * on the chain */
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;
996 m_freem(erdata);
997 } else {
998 #ifdef ARGO_DEBUG
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);
1003 #endif
1004 m->m_len = hdr->tpdu_li;
1005 m_freem(erdata);
1008 hdr->tpdu_li--;
1009 #ifdef TPPT
1010 if (tp_traceflags[D_ERROR_EMIT]) {
1011 tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li + 1, 0, 0);
1013 #endif
1015 datalen = m_datalen(m);
1016 if (tpcb) {
1017 if (tpcb->tp_use_checksum) {
1018 #ifdef TPPT
1019 if (tp_traceflags[D_ERROR_EMIT]) {
1020 tptrace(TPPTmisc, "before gen csum datalen", datalen, 0, 0, 0);
1022 #endif
1023 #ifdef ARGO_DEBUG
1024 if (argo_debug[D_ERROR_EMIT]) {
1025 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
1026 datalen, csum_offset);
1028 #endif
1030 iso_gen_csum(m, csum_offset, datalen);
1032 #ifdef ARGO_DEBUG
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);
1037 #endif
1039 if (cons_channel) {
1040 printf("TP panic! cons channel %p but not cons configured\n",
1041 cons_channel);
1042 return 0;
1043 } else if (tpcb) {
1045 #ifdef ARGO_DEBUG
1046 if (argo_debug[D_ERROR_EMIT]) {
1047 printf("tp_error_emit 1 sending DG: Laddr\n");
1048 dump_addr(sisotosa(laddr));
1049 printf("Faddr\n");
1050 dump_addr(sisotosa(faddr));
1052 #endif
1053 return (*tpcb->tp_nlproto->nlp_dgoutput) (m, datalen,
1054 &laddr->siso_addr,
1055 &faddr->siso_addr,
1056 /* no route */ (void *) 0, !tpcb->tp_use_checksum);
1057 } else if (dgout_routine) {
1058 #ifdef ARGO_DEBUG
1059 if (argo_debug[D_ERROR_EMIT]) {
1060 printf("tp_error_emit sending DG: Laddr\n");
1061 dump_addr(sisotosa(laddr));
1062 printf("Faddr\n");
1063 dump_addr(sisotosa(faddr));
1065 #endif
1066 return (*dgout_routine) (m, datalen, &laddr->siso_addr, &faddr->siso_addr,
1067 (void *) 0, /* nochecksum==false */ 0);
1068 } else {
1069 #ifdef ARGO_DEBUG
1070 if (argo_debug[D_ERROR_EMIT]) {
1071 printf("tp_error_emit DROPPING %p\n", m);
1073 #endif
1074 IncStat(ts_send_drop);
1075 m_freem(m);
1076 return 0;