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