This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / sys / netiso / tp_emit.c
CommitLineData
15637ed4
RG
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
78ed81a3 33 * from: @(#)tp_emit.c 7.9 (Berkeley) 5/9/91
34 * $Id$
15637ed4
RG
35 */
36
37/***********************************************************
38 Copyright IBM Corporation 1987
39
40 All Rights Reserved
41
42Permission to use, copy, modify, and distribute this software and its
43documentation for any purpose and without fee is hereby granted,
44provided that the above copyright notice appear in all copies and that
45both that copyright notice and this permission notice appear in
46supporting documentation, and that the name of IBM not be
47used in advertising or publicity pertaining to distribution of the
48software without specific, written prior permission.
49
50IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
51ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
52IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
53ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
54WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
55ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
56SOFTWARE.
57
58******************************************************************/
59
60/*
61 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
62 */
78ed81a3 63
15637ed4
RG
64/*
65 * ARGO TP
66 *
15637ed4
RG
67 * This file contains tp_emit() and tp_error_emit(), which
68 * form TPDUs and hand them to ip.
69 * They take data in the form of mbuf chain, allocate mbufs as
70 * necessary for headers, and set the fields as appropriate from
71 * information found in the tpcb and net-level pcb.
72 *
73 * The worst thing about this code is adding the variable-length
74 * options on a machine that requires alignment for any memory access
75 * that isn't of size 1. See the macro ADDOPTION() below.
76 *
77 * We don't do any concatenation. (There's a kludge to test the
78 * basic mechanism of separation under the 'w' tpdebug option, that's all.)
79 */
80
81#include "param.h"
78ed81a3 82#include "systm.h"
15637ed4
RG
83#include "mbuf.h"
84#include "socket.h"
85#include "socketvar.h"
86#include "protosw.h"
87#include "errno.h"
88#include "types.h"
89#include "time.h"
90#include "iso.h"
91#include "iso_pcb.h"
92#include "argo_debug.h"
93#include "tp_timer.h"
94#include "tp_param.h"
95#include "tp_stat.h"
96#include "tp_pcb.h"
97#include "tp_tpdu.h"
98#include "tp_trace.h"
99#include "tp_meas.h"
100#include "tp_seq.h"
101#include "iso_errno.h"
102
103#include "../net/if.h"
104#ifdef TRUE
105#undef FALSE
106#undef TRUE
107#endif
108#include "../netccitt/x25.h"
109#include "../netccitt/pk.h"
110#include "../netccitt/pk_var.h"
111
112void iso_gen_csum();
113
114
115/* Here is a mighty kludge. The token ring misorders packets if you
116 * fire them at it too fast, and TP sans checksum is "too fast", so
117 * we have introduced a delay when checksumming isn't used.
118 */
119char tp_delay = 0x00; /* delay to keep token ring from blowing it */
120
121/*
122 * NAME: tp_emit()
123 *
124 * CALLED FROM: tp.trans and from tp_sbsend()
125 *
126 * FUNCTION and ARGUMENTS:
127 * Emits one tpdu of the type (dutype), of the format appropriate
128 * to the connection described by the pcb (tpcb), with sequence
129 * number (seq) (where appropriate), end-of-tsdu bit (eot) where
130 * appropriate, and with the data in the mbuf chain (data).
131 * For DR and ER tpdus, the argument (eot) is
132 * the reason for issuing the tpdu rather than an end-of-tsdu indicator.
133 *
134 * RETURNS:
135 * 0 OK
136 * ENOBUFS
137 * E* returned from net layer output rtn
138 *
139 * SIDE EFFECTS:
140 *
141 * NOTES:
142 *
143 * WE ASSUME that the tp header + all options will fit in ONE mbuf.
144 * If mbufs are 256 this will most likely be true, but if they are 128 it's
145 * possible that they won't.
146 * If you used every option on the CR + max. user data you'd overrun
147 * 112 but unless you used > 115 bytes for the security
148 * parameter, it would fit in a 256-byte mbuf (240 bytes for the header)
149 * We don't support the security parameter, so this isn't a problem.
150 * If security is added, we ought to remove this assumption.
151 *
152 * We do not implement the flow control confirmation "element of procedure".
153 * A) it should not affect interoperability,
154 * B) it should not be necessary - the protocol will eventually
155 * straighten things out w/o FCC, as long as we don't have severely
156 * mismatched keepalive and inactivity timers, and
157 * C) it appears not to be REQUIRED, and
158 * D) it's incredibly grotesque, and no doubt will lengthen a few
159 * critical paths.
160 * HOWEVER, we're thinking about putting it in anyway, for
161 * completeness, just like we did with ack subsequencing.
162 */
163
164int
165tp_emit(dutype, tpcb, seq, eot, data)
166 int dutype;
167 struct tp_pcb *tpcb;
168 SeqNum seq;
169 u_int eot;
170 struct mbuf *data;
171{
172 register struct tpdu *hdr;
173 register struct mbuf *m;
174 int csum_offset=0;
175 int datalen = 0;
176 int error = 0;
177
178 /* NOTE:
179 * here we treat tpdu_li as if it DID include the li field, up until
180 * the end, at which time we subtract 1
181 * THis is because if we subtract 1 right away, we end up adding
182 * one every time we add an option.
183 */
184 IFDEBUG(D_EMIT)
185 printf(
186 "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x",
187 dutype, tpcb, eot, seq, data);
188 ENDDEBUG
189
190 if (dutype == CR_TPDU || dutype == CC_TPDU) {
191 m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT);
192 if (m) {
193 m->m_type = TPMT_TPHDR;
194 mbstat.m_mtypes[TPMT_TPHDR]++;
195 m->m_next = MNULL;
196 m->m_nextpkt = MNULL;
197 m->m_data = m->m_pktdat;
198 m->m_flags = M_PKTHDR;
199 }
200 } else {
201 MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
202 }
203 m->m_data += max_hdr;
204 if (m == NULL) {
205 if(data != (struct mbuf *)0)
206 m_freem(data);
207 error = ENOBUFS;
208 goto done;
209 }
210 m->m_len = sizeof(struct tpdu);
211 m->m_act = MNULL;
212
213 hdr = mtod(m, struct tpdu *);
214 bzero((caddr_t)hdr, sizeof(struct tpdu));
215
216 {
217 int tp_headersize();
218
219 hdr->tpdu_type = dutype;
220 hdr->tpdu_li = tp_headersize(dutype, tpcb);
221 /*
222 * class 0 doesn't use this for DT
223 * it'll just get overwritten below
224 */
225 hdr->tpdu_dref = htons(tpcb->tp_fref);
226 if( tpcb->tp_use_checksum ||
227 (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) {
228 csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */
229 ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */);
230 IFDEBUG(D_CHKSUM)
231 printf(
232 "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
233 csum_offset, hdr->tpdu_li);
234 ENDDEBUG
235 }
236 /*
237 * VARIABLE PARTS...
238 */
239 switch( dutype ) {
240
241 case CR_TPDU_type:
242 hdr->tpdu_CRdref_0 = 0; /* must be zero */
243 if (!tpcb->tp_cebit_off) {
244 tpcb->tp_win_recv = tp_start_win << 8;
245 LOCAL_CREDIT(tpcb);
246 CONG_INIT_SAMPLE(tpcb);
247 tpcb->tp_ackrcvd = 0;
248 }
249 else
250 LOCAL_CREDIT(tpcb);
251
252
253 case CC_TPDU_type:
254 {
255 u_char x;
256
257 hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */
258
259 if( tpcb->tp_class > TP_CLASS_1 ) {
260/* ifdef CE_BIT, we did this in tp_input when the CR came in */
261 if (tpcb->tp_cebit_off)
262 LOCAL_CREDIT( tpcb );
263 tpcb->tp_sent_uwe = tpcb->tp_lcredit -1;
264 tpcb->tp_sent_rcvnxt = 1;
265 tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
266 hdr->tpdu_cdt = tpcb->tp_lcredit;
267 } else {
268#ifdef TPCONS
269 if (tpcb->tp_netservice == ISO_CONS) {
270 struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb;
271 struct pklcd *lcp = (struct pklcd *)(isop->isop_chan);
272 lcp->lcd_flags &= ~X25_DG_CIRCUIT;
273 }
274#endif
275 hdr->tpdu_cdt = 0;
276 }
277 hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class);
278 hdr->tpdu_CCoptions =
279 (tpcb->tp_xtd_format? TPO_XTD_FMT:0) |
280 (tpcb->tp_use_efc? TPO_USE_EFC:0);
281
282 IFPERF(tpcb)
283 u_char perf_meas = tpcb->tp_perf_on;
284 ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas);
285 ENDPERF
286
287 if( dutype == CR_TPDU_type ) {
288 IncStat(ts_CR_sent);
289
290 ASSERT( tpcb->tp_lsuffixlen > 0 );
291 ASSERT( tpcb->tp_fsuffixlen > 0 );
292
293 ADDOPTION(TPP_calling_sufx, hdr,
294 tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
295 ADDOPTION(TPP_called_sufx, hdr,
296 tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
297 } else {
298 IncStat(ts_CC_sent);
299 }
300
301 ADDOPTION(TPP_tpdu_size, hdr,
302 sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
303
304 if (tpcb->tp_class != TP_CLASS_0) {
305 short millisec = 500*(tpcb->tp_sendack_ticks);
306
307 millisec = htons(millisec);
308 ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
309
310 x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0)
311 | (tpcb->tp_use_rcc? TPAO_USE_RCC : 0)
312 | (tpcb->tp_use_checksum?0: TPAO_NO_CSUM)
313 | (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0);
314 ADDOPTION(TPP_addl_opt, hdr, 1, x);
315
316 }
317
318 if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){
319
320 ASSERT( 1 == sizeof(tpcb->tp_vers) );
321 ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
322
323 /* for each alt protocol class x,
324 * x = x<<4;
325 * option = concat(option, x);
326 * Well, for now we only have TP0 for an
327 * alternative so... this is easy.
328 *
329 * HOWEVER... There should be NO alt protocol
330 * class over CLNS. Need to see if the route suggests
331 * CONS, and iff so add alt class.
332 */
333 x = 0;
334 ADDOPTION(TPP_alt_class, hdr, 1, x);
335 }
336
337 if( hdr->tpdu_li > MLEN)
338 panic("tp_emit CR/CC");
339 }
340 break;
341
342 case DR_TPDU_type:
343 if( hdr->tpdu_DRdref == 0 ) {
344 /* don't issue the DR */
345 goto done;
346 }
347 hdr->tpdu_cdt = 0;
348 hdr->tpdu_DRsref = htons(tpcb->tp_lref);
349 hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */
350
351 /* forget the add'l information variable part */
352 IncStat(ts_DR_sent);
353 break;
354
355 case DC_TPDU_type: /* not used in class 0 */
356 ASSERT( tpcb->tp_class != TP_CLASS_0);
357 hdr->tpdu_DCsref = htons(tpcb->tp_lref);
358 hdr->tpdu_cdt = 0;
359 data = (struct mbuf *)0;
360 IncStat(ts_DC_sent);
361 break;
362
363 case XAK_TPDU_type: /* xak not used in class 0 */
364 ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
365 hdr->tpdu_cdt = 0;
366
367 IFTRACE(D_XPD)
368 tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
369 ENDTRACE
370 data = (struct mbuf *)0;
371 if (tpcb->tp_xtd_format) {
372#ifdef BYTE_ORDER
373 union seq_type seqeotX;
374
375 seqeotX.s_seq = seq;
376 seqeotX.s_eot = 1;
377 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
378#else
379 hdr->tpdu_XAKseqX = seq;
380#endif BYTE_ORDER
381 } else {
382 hdr->tpdu_XAKseq = seq;
383 }
384 IncStat(ts_XAK_sent);
385 IncPStat(tpcb, tps_XAK_sent);
386 break;
387
388 case XPD_TPDU_type: /* xpd not used in class 0 */
389 ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */
390 hdr->tpdu_cdt = 0;
391 if (tpcb->tp_xtd_format) {
392#ifdef BYTE_ORDER
393 union seq_type seqeotX;
394
395 seqeotX.s_seq = seq;
396 seqeotX.s_eot = 1;
397 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
398#else
399 hdr->tpdu_XPDseqX = seq;
400 hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
401#endif BYTE_ORDER
402 } else {
403 hdr->tpdu_XPDseq = seq;
404 hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
405 }
406 IncStat(ts_XPD_sent);
407 IncPStat(tpcb, tps_XPD_sent);
408
409 /* kludge to test the input size checking */
410 IFDEBUG(D_SIZE_CHECK)
411 /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) {
412 printf("Sending too much data on XPD: 18 bytes\n");
413 data->m_len = 18;
414 }*/
415 ENDDEBUG
416 break;
417
418 case DT_TPDU_type:
419 hdr->tpdu_cdt = 0;
420 IFTRACE(D_DATA)
421 tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq,
422 hdr->tpdu_li, 0);
423 ENDTRACE
424 if (tpcb->tp_xtd_format) {
425#ifdef BYTE_ORDER
426 union seq_type seqeotX;
427
428 seqeotX.s_seq = seq;
429 seqeotX.s_eot = eot;
430 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
431#else
432 hdr->tpdu_DTseqX = seq;
433 hdr->tpdu_DTeotX = eot;
434#endif BYTE_ORDER
435 } else if (tpcb->tp_class == TP_CLASS_0) {
436 IFDEBUG(D_EMIT)
437 printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
438 dump_buf( hdr, hdr->tpdu_li + 1 );
439 ENDDEBUG
440 ((struct tp0du *)hdr)->tp0du_eot = eot;
441 ((struct tp0du *)hdr)->tp0du_mbz = 0;
442 IFDEBUG(D_EMIT)
443 printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr);
444 dump_buf( hdr, hdr->tpdu_li + 1 );
445 ENDDEBUG
446 } else {
447 hdr->tpdu_DTseq = seq;
448 hdr->tpdu_DTeot = eot;
449 }
450 if(eot) {
451 IncStat(ts_EOT_sent);
452 }
453 IncStat(ts_DT_sent);
454 IncPStat(tpcb, tps_DT_sent);
455 break;
456
457 case AK_TPDU_type:/* ak not used in class 0 */
458 ASSERT( tpcb->tp_class != TP_CLASS_0);
459 data = (struct mbuf *)0;
460 { SeqNum olduwe = tpcb->tp_sent_uwe;
461
462 tpcb->tp_sent_uwe =
463 SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1);
464 LOCAL_CREDIT( tpcb );
465 tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
466
467 IFDEBUG(D_RENEG)
468 /* occasionally fake a reneging so
469 you can test subsequencing */
470 if( olduwe & 0x1 ) {
471 tpcb->tp_reneged = 1;
472 IncStat(ts_ldebug);
473 }
474 ENDDEBUG
475 /* Are we about to reneg on credit?
476 * When might we do so?
477 * a) when using optimistic credit (which we no longer do).
478 * b) when drain() gets implemented (not in the plans).
479 * c) when D_RENEG is on.
480 * d) when DEC BIT response is implemented.
481 * (not- when we do this, we'll need to implement flow control
482 * confirmation)
483 */
484 if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) {
485 tpcb->tp_reneged = 1;
486 IncStat(ts_lcdt_reduced);
487 IFTRACE(D_CREDIT)
488 tptraceTPCB(TPPTmisc,
489 "RENEG: olduwe newuwe lcredit rcvnxt",
490 olduwe,
491 tpcb->tp_sent_uwe, tpcb->tp_lcredit,
492 tpcb->tp_rcvnxt);
493 ENDTRACE
494 }
495
496 IFPERF(tpcb)
497 /* new lwe is less than old uwe means we're
498 * acking before we received a whole window full
499 */
500 if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) {
501 /* tmp1 = number of pkts fewer than the full window */
502 register int tmp1 =
503 (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt);
504
505 if(tmp1 > TP_PM_MAX)
506 tmp1 = TP_PM_MAX;
507 IncPStat( tpcb, tps_ack_early[tmp1] );
508
509 /* tmp1 = amt of new cdt we're advertising */
510 tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt);
511 if(tmp1 > TP_PM_MAX )
512 tmp1 = TP_PM_MAX;
513
514 IncPStat( tpcb,
515 tps_cdt_acked [ tmp1 ]
516 [ ((tpcb->tp_lcredit > TP_PM_MAX)?
517 TP_PM_MAX:tpcb->tp_lcredit) ] );
518
519 }
520 ENDPERF
521 }
522 IFTRACE(D_ACKSEND)
523 tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe,
524 tpcb->tp_r_subseq, 0);
525 ENDTRACE
526 if (tpcb->tp_xtd_format) {
527#ifdef BYTE_ORDER
528 union seq_type seqeotX;
529
530 seqeotX.s_seq = seq;
531 seqeotX.s_eot = 0;
532 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
533 hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
534#else
535 hdr->tpdu_cdt = 0;
536 hdr->tpdu_AKseqX = seq;
537 hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
538#endif BYTE_ORDER
539 } else {
540 hdr->tpdu_AKseq = seq;
541 hdr->tpdu_AKcdt = tpcb->tp_lcredit;
542 }
543 if ((tpcb->tp_class == TP_CLASS_4) && tpcb->tp_reneged ) {
544 /*
545 * Ack subsequence parameter req'd if WE reneged on
546 * credit offered. (ISO 8073, 12.2.3.8.2, p. 74)
547 */
548 IFDEBUG(D_RENEG)
549 printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
550 ENDDEBUG
551 tpcb->tp_s_subseq++;
552 /*
553 * add tmp subseq and do a htons on it.
554 */
555 ADDOPTION(TPP_subseq, hdr,
556 sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
557 } else
558 tpcb->tp_s_subseq = 0;
559
560 if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ {
561 /*
562 * Rules for sending FCC ("should" send when) :
563 * %a) received an ack from peer with NO NEWS whatsoever,
564 * and it did not contain an FCC
565 * b) received an ack from peer that opens its closed window.
566 * c) received an ack from peer after it reneged on its
567 * offered credit, AND this ack raises UWE but LWE is same
568 * and below UWE at time of reneging (reduction)
569 * Now, ISO 8073 12.2.3.8.3 says
570 * that a retransmitted AK shall not contain the FCC
571 * parameter. Now, how the hell you tell the difference
572 * between a retransmitted ack and an ack that's sent in
573 * response to a received ack, I don't know, because without
574 * any local activity, and w/o any received DTs, they
575 * will contain exactly the same credit/seq# information.
576 * Anyway, given that the "retransmission of acks"
577 * procedure (ISO 8073 12.2.3.8.3) is optional, and we
578 * don't do it (although the peer can't tell that), we
579 * ignore this last rule.
580 *
581 * We send FCC for reasons a) and b) only.
582 * To add reason c) would require a ridiculous amount of state.
583 *
584 */
585 u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */
586 SeqNum lwe;
587 u_short subseq, fcredit;
588
589 tpcb->tp_sendfcc = 0;
590
591 lwe = (SeqNum) htonl(tpcb->tp_snduna);
592 subseq = htons(tpcb->tp_r_subseq);
593 fcredit = htons(tpcb->tp_fcredit);
594
595 bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum));
596 bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short));
597 bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short));
598
599 IFTRACE(D_ACKSEND)
600 tptraceTPCB(TPPTmisc,
601 "emit w/FCC: snduna r_subseq fcredit",
602 tpcb->tp_snduna, tpcb->tp_r_subseq,
603 tpcb->tp_fcredit, 0);
604 ENDTRACE
605
606 IFDEBUG(D_ACKSEND)
607 printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n",
608 TPP_flow_cntl_conf,
609 hdr, sizeof(bogus), bogus[0]);
610 ENDDEBUG
611 ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
612 IFDEBUG(D_ACKSEND)
613 printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n",
614 hdr, hdr->tpdu_li);
615 printf(
616 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
617 csum_offset, hdr->tpdu_li);
618 ENDDEBUG
619
620 }
621 tpcb->tp_reneged = 0;
622 tpcb->tp_sent_rcvnxt = seq;
623 tp_ctimeout(tpcb->tp_refp, TM_sendack,
624 (int)tpcb->tp_keepalive_ticks);
625 IncStat(ts_AK_sent);
626 IncPStat(tpcb, tps_AK_sent);
627 IFDEBUG(D_ACKSEND)
628 printf(
629 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
630 csum_offset, hdr->tpdu_li);
631 ENDDEBUG
632 break;
633
634 case ER_TPDU_type:
635 hdr->tpdu_ERreason = eot;
636 hdr->tpdu_cdt = 0;
637 /* no user data */
638 data = (struct mbuf *)0;
639 IncStat(ts_ER_sent);
640 break;
641 }
642
643 }
644 ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) );
645
646 m->m_next = data;
647
648 ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */
649 ASSERT( hdr->tpdu_li != 0 ); /* leave this in */
650
651 m->m_len = hdr->tpdu_li ;
652 hdr->tpdu_li --; /* doesn't include the li field */
653
654 datalen = m_datalen( m ); /* total len */
655
656 ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem
657 when CLNP is used; leave in here for the time being */
658 IFDEBUG(D_ACKSEND)
659 printf(
660 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
661 csum_offset, hdr->tpdu_li);
662 ENDDEBUG
663 if( datalen > tpcb->tp_l_tpdusize ) {
664 printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
665 datalen, tpcb->tp_l_tpdusize);
666 }
667 IFDEBUG(D_EMIT)
668 printf(
669 "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
670 m->m_len, csum_offset, datalen);
671 ENDDEBUG
672 if( tpcb->tp_use_checksum ||
673 (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) {
674 iso_gen_csum(m, csum_offset, datalen);
675 }
676
677 IFDEBUG(D_EMIT)
678 printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n",
679 tpcb, dutype, datalen);
680 dump_buf(mtod(m, caddr_t), datalen);
681 ENDDEBUG
682
683 IFPERF(tpcb)
684 if( dutype == DT_TPDU_type ) {
685 PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
686 tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0,
687 seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len));
688 }
689 ENDPERF
690
691 IFTRACE(D_EMIT)
692 tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0);
693 ENDTRACE
694 IFDEBUG(D_EMIT)
695 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
696 tpcb, tpcb->tp_npcb, tpcb->tp_sock);
697 ENDDEBUG
698
699 { extern char tp_delay;
700
701 if( tp_delay )
702 if( tpcb->tp_use_checksum == 0 ) {
703 register u_int i = tp_delay;
704 for (; i!= 0; i--)
705 (void) iso_check_csum(m, datalen);
706 }
707 }
708 ASSERT( m->m_len > 0 );
709 error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen,
710 !tpcb->tp_use_checksum);
711 IFDEBUG(D_EMIT)
712 printf("OUTPUT: returned 0x%x\n", error);
713 ENDDEBUG
714 IFTRACE(D_EMIT)
715 tptraceTPCB(TPPTmisc,
716 "tp_emit nlproto->output netservice returns datalen",
717 tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
718 ENDTRACE
719done:
720 if( error == E_CO_QFULL ) {
721 tp_quench(tpcb, PRC_QUENCH);
722 return 0;
723 }
724 return error;
725}
726/*
727 * NAME: tp_error_emit()
728 * CALLED FROM: tp_input() when a DR or ER is to be issued in
729 * response to an input error.
730 * FUNCTION and ARGUMENTS:
731 * The error type is the first argument.
732 * The argument (sref) is the source reference on the bad incoming tpdu,
733 * and is used for a destination reference on the outgoing packet.
734 * (faddr) and (laddr) are the foreign and local addresses for this
735 * connection.
736 * (erdata) is a ptr to the errant incoming tpdu, and is copied into the
737 * outgoing ER, if an ER is to be issued.
738 * (erlen) is the number of octets of the errant tpdu that we should
739 * try to copy.
740 * (tpcb) is the pcb that describes the connection for which the bad tpdu
741 * arrived.
742 * RETURN VALUES:
743 * 0 OK
744 * ENOBUFS
745 * E* from net layer datagram output routine
746 * SIDE EFFECTS:
747 *
748 * NOTES:
749 */
750
751int
752tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel,
753 dgout_routine)
754 int error;
755 u_long sref;
756 struct sockaddr_iso *faddr, *laddr;
757 struct mbuf *erdata;
758 int erlen;
759 struct tp_pcb *tpcb;
760 int cons_channel;
761 int (*dgout_routine)();
762{
763 int dutype;
764 int datalen = 0;
765 register struct tpdu *hdr;
766 register struct mbuf *m;
767 int csum_offset;
768
769 IFTRACE(D_ERROR_EMIT)
770 tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
771 error, sref, tpcb, erlen);
772 ENDTRACE
773 IFDEBUG(D_ERROR_EMIT)
774 printf(
775 "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n",
776 error, sref, tpcb, erlen, cons_channel);
777 ENDDEBUG
778
779 MGET(m, M_DONTWAIT, TPMT_TPHDR);
780 if (m == NULL) {
781 return ENOBUFS;
782 }
783 m->m_len = sizeof(struct tpdu);
784 m->m_act = MNULL;
785
786 hdr = mtod(m, struct tpdu *);
787
788 IFDEBUG(D_ERROR_EMIT)
789 printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
790 error, error&0xff, (char)error);
791 ENDDEBUG
792
793
794 if (error & TP_ERROR_SNDC)
795 dutype = DC_TPDU_type;
796 else if (error & 0x40) {
797 error &= ~0x40;
798 dutype = ER_TPDU_type;
799 } else
800 dutype = DR_TPDU_type;
801 error &= 0xff;
802
803 hdr->tpdu_type = dutype;
804 hdr->tpdu_cdt = 0;
805
806 switch( dutype ) {
807
808 case DC_TPDU_type:
809 IncStat(ts_DC_sent);
810 hdr->tpdu_li = 6;
811 hdr->tpdu_DCdref = htons(sref);
812 hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
813 IFDEBUG(D_ERROR_EMIT)
814 printf("DC case:\n");
815 dump_buf( hdr, 6);
816 ENDDEBUG
817 /* forget the add'l information variable part */
818 break;
819
820 case DR_TPDU_type:
821 IncStat(ts_DR_sent);
822 hdr->tpdu_li = 7;
823 hdr->tpdu_DRdref = htons(sref);
824 hdr->tpdu_DRsref = 0;
825 hdr->tpdu_DRreason = (char)error;
826 IFDEBUG(D_ERROR_EMIT)
827 printf("DR case:\n");
828 dump_buf( hdr, 7);
829 ENDDEBUG
830 /* forget the add'l information variable part */
831 break;
832
833 case ER_TPDU_type:
834 IncStat(ts_ER_sent);
835 hdr->tpdu_li = 5;
836 hdr->tpdu_ERreason = (char)error;
837 break;
838
839 default:
840 ASSERT(0);
841 printf("TP PANIC: bad dutype 0x%x\n", dutype);
842 }
843
844 if(tpcb)
845 if( tpcb->tp_use_checksum ) {
846 ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */);
847 csum_offset = hdr->tpdu_li - 2;
848 }
849
850 ASSERT( hdr->tpdu_li < MLEN );
851
852 if (dutype == ER_TPDU_type) {
853 /* copy the errant tpdu into another 'variable part' */
854 register caddr_t P;
855
856 IFTRACE(D_ERROR_EMIT)
857 tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
858 0,0);
859 ENDTRACE
860 IFDEBUG(D_ERROR_EMIT)
861 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
862 ENDDEBUG
863
864 /* copy at most as many octets for which you have room */
865 if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
866 erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
867
868 /* add the "invalid tpdu" parameter : required in class 0 */
869 P = (caddr_t)hdr + (int)(hdr->tpdu_li);
870 vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */
871 vbptr(P)->tpv_len = erlen; /* parameter length */
872 m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
873
874 /* tp_input very likely handed us an mbuf chain w/ nothing in
875 * the first mbuf and the data following the empty mbuf
876 */
877 if(erdata->m_len == 0) {
878 erdata = m_free(erdata); /* returns the next mbuf on the chain */
879 }
880 /*
881 * copy only up to the bad octet
882 * (or max that will fit in a header
883 */
884 m->m_next = m_copy(erdata, 0, erlen);
885 hdr->tpdu_li += erlen + 2;
886 m_freem(erdata);
887 } else {
888 IFDEBUG(D_ERROR_EMIT)
889 printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li);
890 dump_buf( (char *)hdr, hdr->tpdu_li );
891 ENDDEBUG
892 m->m_len = hdr->tpdu_li ;
893 m_freem(erdata);
894 }
895
896 hdr->tpdu_li --;
897 IFTRACE(D_ERROR_EMIT)
898 tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0);
899 ENDTRACE
900
901 datalen = m_datalen( m);
902
903 if(tpcb) {
904 if( tpcb->tp_use_checksum ) {
905 IFTRACE(D_ERROR_EMIT)
906 tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0);
907 ENDTRACE
908 IFDEBUG(D_ERROR_EMIT)
909 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
910 datalen, csum_offset);
911 ENDDEBUG
912
913 iso_gen_csum(m, csum_offset, datalen);
914 }
915
916 IFDEBUG(D_ERROR_EMIT)
917 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n",
918 tpcb, tpcb->tp_npcb, tpcb->tp_sock);
919 ENDDEBUG
920 /* Problem: if packet comes in on ISO but sock is listening
921 * in INET, this assertion will fail.
922 * Have to believe the argument, not the nlp_proto.
923 ASSERT( tpcb->tp_nlproto->nlp_dgoutput == dgout_routine );
924 */
925
926 IFDEBUG(D_ERROR_EMIT)
927 printf("tp_error_emit 1 sending DG: Laddr\n");
928 dump_addr((struct sockaddr *)laddr);
929 printf("Faddr\n");
930 dump_addr((struct sockaddr *)faddr);
931 ENDDEBUG
932 return (tpcb->tp_nlproto->nlp_dgoutput)(
933 &laddr->siso_addr,
934 &faddr->siso_addr,
935 m, datalen,
936 /* no route */ (caddr_t)0, !tpcb->tp_use_checksum);
937 } else {
938 if( cons_channel ) {
939#ifdef TPCONS
940 tpcons_dg_output(cons_channel, m, datalen);
941 pk_disconnect((struct pklcd *)cons_channel);
942 IFDEBUG(D_ERROR_EMIT)
943 printf("OUTPUT: dutype 0x%x channel 0x%x\n",
944 dutype, cons_channel);
945 ENDDEBUG
946#else
947 printf("TP panic! cons channel 0x%x but not cons configured\n",
948 cons_channel);
949#endif
950 } else {
951#ifndef notdef
952 IFDEBUG(D_ERROR_EMIT)
953 printf("tp_error_emit sending DG: Laddr\n");
954 dump_addr((struct sockaddr *)laddr);
955 printf("Faddr\n");
956 dump_addr((struct sockaddr *)faddr);
957 ENDDEBUG
958 return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr,
959 m, datalen, /* no route */
960 (caddr_t)0, /* nochecksum==false */0);
961#else notdef
962 IFDEBUG(D_ERROR_EMIT)
963 printf("tp_error_emit DROPPING \n", m);
964 ENDDEBUG
965 IncStat(ts_send_drop);
966 m_freem(m);
967 return 0;
968#endif notdef
969 }
970 }
971}