FreeBSD/Linux Kernel Cross Reference
sys/netiso/tp_emit.c
1 /* $NetBSD: tp_emit.c,v 1.21 2005/02/26 22:39:49 perry Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
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.
18 *
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.
30 *
31 * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93
32 */
33
34 /***********************************************************
35 Copyright IBM Corporation 1987
36
37 All Rights Reserved
38
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.
46
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.
54
55 ******************************************************************/
56
57 /*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60 /*
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.
65 *
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.
69 *
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.)
72 */
73
74 #include <sys/cdefs.h>
75 __KERNEL_RCSID(0, "$NetBSD: tp_emit.c,v 1.21 2005/02/26 22:39:49 perry Exp $");
76
77 #include "opt_iso.h"
78
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>
87
88 #include <net/if.h>
89
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>
104
105 #ifdef TRUE
106 #undef FALSE
107 #undef TRUE
108 #endif
109 #include <netccitt/x25.h>
110 #include <netccitt/pk.h>
111 #include <netccitt/pk_var.h>
112
113 /*
114 * Here is a mighty kludge. The token ring misorders packets if you fire
115 * them at it too fast, and TP sans checksum is "too fast", so we have
116 * introduced a delay when checksumming isn't used.
117 */
118 char 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
163 int
164 tp_emit(
165 int dutype,
166 struct tp_pcb *tpcb,
167 SeqNum seq,
168 u_int eot,
169 struct mbuf *data)
170 {
171 struct tpdu *hdr;
172 struct mbuf *m;
173 int csum_offset = 0;
174 int datalen = 0;
175 int error = 0;
176 SeqNum olduwe;
177 int acking_ooo;
178
179 /*
180 * NOTE: here we treat tpdu_li as if it DID include the li field, up
181 * until the end, at which time we subtract 1 THis is because if we
182 * subtract 1 right away, we end up adding one every time we add an
183 * option.
184 */
185 #ifdef ARGO_DEBUG
186 if (argo_debug[D_EMIT]) {
187 printf(
188 "tp_emit dutype 0x%x, tpcb %p, eot 0x%x, seq 0x%x, data %p",
189 dutype, tpcb, eot, seq, data);
190 }
191 #endif
192
193 if (dutype == CR_TPDU || dutype == CC_TPDU) {
194 m = (struct mbuf *) malloc((u_long) 256, M_MBUF, M_DONTWAIT);
195 if (m) {
196 m->m_type = TPMT_TPHDR;
197 mbstat.m_mtypes[TPMT_TPHDR]++;
198 m->m_next = NULL;
199 m->m_nextpkt = NULL;
200 m->m_data = m->m_pktdat;
201 m->m_flags = M_PKTHDR;
202 bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
203 }
204 } else {
205 MGETHDR(m, M_DONTWAIT, TPMT_TPHDR);
206 }
207 m->m_data += max_hdr;
208 if (m == NULL) {
209 if (data != (struct mbuf *) 0)
210 m_freem(data);
211 error = ENOBUFS;
212 goto done;
213 }
214 m->m_len = sizeof(struct tpdu);
215 m->m_nextpkt = NULL;
216
217 hdr = mtod(m, struct tpdu *);
218 bzero((caddr_t) hdr, sizeof(struct tpdu));
219
220 {
221 hdr->tpdu_type = dutype;
222 hdr->tpdu_li = tp_headersize(dutype, tpcb);
223 /*
224 * class 0 doesn't use this for DT
225 * it'll just get overwritten below
226 */
227 hdr->tpdu_dref = htons(tpcb->tp_fref);
228 if (tpcb->tp_use_checksum ||
229 (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4))) {
230 csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */
231 ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */ );
232 #ifdef ARGO_DEBUG
233 if (argo_debug[D_CHKSUM]) {
234 printf(
235 "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
236 csum_offset, hdr->tpdu_li);
237 }
238 #endif
239 }
240 /*
241 * VARIABLE PARTS...
242 */
243 switch (dutype) {
244
245 case CR_TPDU_type:
246 hdr->tpdu_CRdref_0 = 0; /* must be zero */
247 case CC_TPDU_type:
248 if (!tpcb->tp_cebit_off) {
249 tpcb->tp_win_recv = tp_start_win << 8;
250 LOCAL_CREDIT(tpcb);
251 CONG_INIT_SAMPLE(tpcb);
252 } else
253 LOCAL_CREDIT(tpcb);
254
255 /* Case CC_TPDU_type used to be here */
256 {
257 u_char x;
258
259 hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */
260
261 if (tpcb->tp_class > TP_CLASS_1) {
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 #ifdef TP_PERF_MEAS
282 if (DOPERF(tpcb)) {
283 u_char perf_meas = tpcb->tp_perf_on;
284 ADDOPTION(TPP_perf_meas, hdr,
285 sizeof(perf_meas), perf_meas);
286 }
287 #endif
288
289 if (dutype == CR_TPDU_type) {
290 IncStat(ts_CR_sent);
291
292 ASSERT(tpcb->tp_lsuffixlen > 0);
293 ASSERT(tpcb->tp_fsuffixlen > 0);
294
295 ADDOPTION(TPP_calling_sufx, hdr,
296 tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]);
297 ADDOPTION(TPP_called_sufx, hdr,
298 tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]);
299 } else {
300 IncStat(ts_CC_sent);
301 }
302
303 ADDOPTION(TPP_tpdu_size, hdr,
304 sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize);
305
306 if (tpcb->tp_class != TP_CLASS_0) {
307 short millisec = 500 * (tpcb->tp_sendack_ticks);
308
309 millisec = htons(millisec);
310 ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec);
311
312 x = (tpcb->tp_use_nxpd ? TPAO_USE_NXPD : 0)
313 | (tpcb->tp_use_rcc ? TPAO_USE_RCC : 0)
314 | (tpcb->tp_use_checksum ? 0 : TPAO_NO_CSUM)
315 | (tpcb->tp_xpd_service ? TPAO_USE_TXPD : 0);
316 ADDOPTION(TPP_addl_opt, hdr, 1, x);
317
318 if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) {
319 u_short size_s = tpcb->tp_l_tpdusize >> 7;
320 u_char size_c = size_s;
321 ASSERT(tpcb->tp_l_tpdusize < 65536 * 128);
322 if (dutype == CR_TPDU_type)
323 tpcb->tp_ptpdusize = size_s;
324 if (size_s < 256) {
325 ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c);
326 } else {
327 size_s = htons(size_s);
328 ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s);
329 }
330 }
331 }
332 if ((dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)) {
333
334 ASSERT(1 == sizeof(tpcb->tp_vers));
335 ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers);
336
337 /*
338 * for each alt protocol class x, x =
339 * x<<4; option = concat(option, x);
340 * Well, for now we only have TP0 for
341 * an alternative so... this is easy.
342 *
343 * HOWEVER... There should be NO alt
344 * protocol class over CLNS. Need to
345 * see if the route suggests CONS,
346 * and iff so add alt class.
347 */
348 x = 0;
349 ADDOPTION(TPP_alt_class, hdr, 1, x);
350 }
351 #if 0
352 if (hdr->tpdu_li > MLEN)
353 panic("tp_emit CR/CC");
354 #endif
355 }
356 break;
357
358 case DR_TPDU_type:
359 if (hdr->tpdu_DRdref == 0) {
360 /* don't issue the DR */
361 goto done;
362 }
363 hdr->tpdu_cdt = 0;
364 hdr->tpdu_DRsref = htons(tpcb->tp_lref);
365 hdr->tpdu_DRreason = (u_char) eot; /* WHICH BYTE OF THIS??? */
366
367 /* forget the add'l information variable part */
368 IncStat(ts_DR_sent);
369 break;
370
371 case DC_TPDU_type: /* not used in class 0 */
372 ASSERT(tpcb->tp_class != TP_CLASS_0);
373 hdr->tpdu_DCsref = htons(tpcb->tp_lref);
374 hdr->tpdu_cdt = 0;
375 data = (struct mbuf *) 0;
376 IncStat(ts_DC_sent);
377 break;
378
379 case XAK_TPDU_type: /* xak not used in class 0 */
380 ASSERT(tpcb->tp_class != TP_CLASS_0); /* fall through */
381 hdr->tpdu_cdt = 0;
382
383 #ifdef TPPT
384 if (tp_traceflags[D_XPD]) {
385 tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0);
386 }
387 #endif
388 data = (struct mbuf *) 0;
389 if (tpcb->tp_xtd_format) {
390 #ifdef BYTE_ORDER
391 union seq_type seqeotX;
392
393 seqeotX.s_seq = seq;
394 seqeotX.s_eot = 1;
395 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
396 #else
397 hdr->tpdu_XAKseqX = seq;
398 #endif /* BYTE_ORDER */
399 } else {
400 hdr->tpdu_XAKseq = seq;
401 }
402 IncStat(ts_XAK_sent);
403 IncPStat(tpcb, tps_XAK_sent);
404 break;
405
406 case XPD_TPDU_type: /* xpd not used in class 0 */
407 ASSERT(tpcb->tp_class != TP_CLASS_0); /* fall through */
408 hdr->tpdu_cdt = 0;
409 if (tpcb->tp_xtd_format) {
410 #ifdef BYTE_ORDER
411 union seq_type seqeotX;
412
413 seqeotX.s_seq = seq;
414 seqeotX.s_eot = 1;
415 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
416 #else
417 hdr->tpdu_XPDseqX = seq;
418 hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */
419 #endif /* BYTE_ORDER */
420 } else {
421 hdr->tpdu_XPDseq = seq;
422 hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */
423 }
424 IncStat(ts_XPD_sent);
425 IncPStat(tpcb, tps_XPD_sent);
426
427 /* kludge to test the input size checking */
428 #ifdef ARGO_DEBUG
429 if (argo_debug[D_SIZE_CHECK]) {
430 #if 0
431 if (data->m_len <= 16 &&
432 data->m_off < (MLEN-18)) {
433 printf("Sending too much data on XPD: 18 bytes\n");
434 data->m_len = 18;
435 }
436 #endif
437 }
438 #endif
439 break;
440
441 case DT_TPDU_type:
442 hdr->tpdu_cdt = 0;
443 #ifdef TPPT
444 if (tp_traceflags[D_DATA]) {
445 tptraceTPCB(TPPTmisc,
446 "emit DT: eot seq tpdu_li", eot,
447 seq, hdr->tpdu_li, 0);
448 }
449 #endif
450 if (tpcb->tp_xtd_format) {
451 #ifdef BYTE_ORDER
452 union seq_type seqeotX;
453
454 seqeotX.s_seq = seq;
455 seqeotX.s_eot = eot;
456 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
457 #else
458 hdr->tpdu_DTseqX = seq;
459 hdr->tpdu_DTeotX = eot;
460 #endif /* BYTE_ORDER */
461 } else if (tpcb->tp_class == TP_CLASS_0) {
462 #ifdef ARGO_DEBUG
463 if (argo_debug[D_EMIT]) {
464 printf("DT tpdu: class 0 m %p hdr %p\n", m, hdr);
465 dump_buf(hdr, hdr->tpdu_li + 1);
466 }
467 #endif
468 ((struct tp0du *) hdr)->tp0du_eot = eot;
469 ((struct tp0du *) hdr)->tp0du_mbz = 0;
470 #ifdef ARGO_DEBUG
471 if (argo_debug[D_EMIT]) {
472 printf("DT 2 tpdu: class 0 m %p hdr %p\n", m, hdr);
473 dump_buf(hdr, hdr->tpdu_li + 1);
474 }
475 #endif
476 } else {
477 hdr->tpdu_DTseq = seq;
478 hdr->tpdu_DTeot = eot;
479 }
480 if (eot) {
481 IncStat(ts_EOT_sent);
482 }
483 IncStat(ts_DT_sent);
484 IncPStat(tpcb, tps_DT_sent);
485 break;
486
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;
491
492 if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) {
493 LOCAL_CREDIT(tpcb);
494 tpcb->tp_sent_uwe =
495 SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_lcredit - 1);
496 tpcb->tp_sent_lcdt = tpcb->tp_lcredit;
497 acking_ooo = 0;
498 } else
499 acking_ooo = 1;
500
501 #ifdef ARGO_DEBUG
502 if (argo_debug[D_RENEG]) {
503 /*
504 * occasionally fake a reneging so you can test
505 * subsequencing
506 */
507 if (olduwe & 0x1) {
508 tpcb->tp_reneged = 1;
509 IncStat(ts_ldebug);
510 }
511 }
512 #endif
513 /*
514 * Are we about to reneg on credit? When might we do
515 * so? a) when using optimistic credit (which we no
516 * longer do). b) when drain() gets implemented (not
517 * in the plans). c) when D_RENEG is on. d) when DEC
518 * BIT response is implemented. (not- when we do
519 * this, we'll need to implement flow control
520 * confirmation)
521 */
522 if (SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe)) {
523 tpcb->tp_reneged = 1;
524 IncStat(ts_lcdt_reduced);
525 #ifdef TPPT
526 if (tp_traceflags[D_CREDIT]) {
527 tptraceTPCB(TPPTmisc,
528 "RENEG: olduwe newuwe lcredit rcvnxt",
529 olduwe,
530 tpcb->tp_sent_uwe, tpcb->tp_lcredit,
531 tpcb->tp_rcvnxt);
532 }
533 #endif
534 }
535 #ifdef TP_PERF_MEAS
536 if (DOPERF(tpcb)) {
537 /*
538 * new lwe is less than old uwe means we're
539 * acking before we received a whole window full
540 */
541 if (SEQ_LT(tpcb, tpcb->tp_rcvnxt, olduwe)) {
542 /*
543 * tmp1 = number of pkts fewer than
544 * the full window
545 */
546 int tmp1 =
547 (int) SEQ_SUB(tpcb, olduwe,
548 tpcb->tp_rcvnxt);
549
550 if (tmp1 > TP_PM_MAX)
551 tmp1 = TP_PM_MAX;
552 IncPStat(tpcb, tps_ack_early[tmp1]);
553
554 /*
555 * tmp1 = amt of new cdt we're
556 * advertising
557 */
558 tmp1 = SEQ_SUB(tpcb, seq,
559 tpcb->tp_sent_rcvnxt);
560 if (tmp1 > TP_PM_MAX)
561 tmp1 = TP_PM_MAX;
562
563 IncPStat(tpcb,
564 tps_cdt_acked[tmp1]
565 [((tpcb->tp_lcredit >
566 TP_PM_MAX) ?
567 TP_PM_MAX :
568 tpcb->tp_lcredit)]);
569
570 }
571 }
572 #endif
573
574 #ifdef TPPT
575 if (tp_traceflags[D_ACKSEND]) {
576 tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit,
577 tpcb->tp_sent_uwe,
578 tpcb->tp_r_subseq, 0);
579 }
580 #endif
581 if (tpcb->tp_xtd_format) {
582 #ifdef BYTE_ORDER
583 union seq_type seqeotX;
584
585 seqeotX.s_seq = seq;
586 seqeotX.s_eot = 0;
587 hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot);
588 hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit);
589 #else
590 hdr->tpdu_cdt = 0;
591 hdr->tpdu_AKseqX = seq;
592 hdr->tpdu_AKcdtX = tpcb->tp_lcredit;
593 #endif /* BYTE_ORDER */
594 } else {
595 hdr->tpdu_AKseq = seq;
596 hdr->tpdu_AKcdt = tpcb->tp_lcredit;
597 }
598 if ((tpcb->tp_class == TP_CLASS_4) &&
599 (tpcb->tp_reneged || acking_ooo)) {
600 /*
601 * Ack subsequence parameter req'd if WE
602 * reneged on credit offered. (ISO 8073,
603 * 12.2.3.8.2, p. 74)
604 */
605 #ifdef ARGO_DEBUG
606 if (argo_debug[D_RENEG]) {
607 printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq);
608 }
609 #endif
610 tpcb->tp_s_subseq++;
611 /*
612 * add tmp subseq and do a htons on it.
613 */
614 ADDOPTION(TPP_subseq, hdr,
615 sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq);
616 } else
617 tpcb->tp_s_subseq = 0;
618
619 if (tpcb->tp_sendfcc || eot) { /* overloaded to mean
620 * SEND FCC */
621 /*
622 * Rules for sending FCC ("should" send when)
623 * : %a) received an ack from peer with NO
624 * NEWS whatsoever, and it did not contain an
625 * FCC b) received an ack from peer that
626 * opens its closed window. c) received an
627 * ack from peer after it reneged on its
628 * offered credit, AND this ack raises UWE
629 * but LWE is same and below UWE at time of
630 * reneging (reduction) Now, ISO 8073
631 * 12.2.3.8.3 says that a retransmitted AK
632 * shall not contain the FCC parameter. Now,
633 * how the hell you tell the difference
634 * between a retransmitted ack and an ack
635 * that's sent in response to a received ack,
636 * I don't know, because without any local
637 * activity, and w/o any received DTs, they
638 * will contain exactly the same credit/seq#
639 * information. Anyway, given that the
640 * "retransmission of acks" procedure (ISO
641 * 8073 12.2.3.8.3) is optional, and we don't
642 * do it (although the peer can't tell that),
643 * we ignore this last rule.
644 *
645 * We send FCC for reasons a) and b) only. To
646 * add reason c) would require a ridiculous
647 * amount of state.
648 *
649 */
650 u_short bogus[4]; /* lwe(32), subseq(16),
651 * cdt(16) */
652 SeqNum lwe;
653 u_short subseq, fcredit;
654
655 tpcb->tp_sendfcc = 0;
656
657 lwe = (SeqNum) htonl(tpcb->tp_snduna);
658 subseq = htons(tpcb->tp_r_subseq);
659 fcredit = htons(tpcb->tp_fcredit);
660
661 bcopy((caddr_t) & lwe, (caddr_t) & bogus[0], sizeof(SeqNum));
662 bcopy((caddr_t) & subseq, (caddr_t) & bogus[2], sizeof(u_short));
663 bcopy((caddr_t) & fcredit, (caddr_t) & bogus[3], sizeof(u_short));
664
665 #ifdef TPPT
666 if (tp_traceflags[D_ACKSEND]) {
667 tptraceTPCB(TPPTmisc,
668 "emit w/FCC: snduna r_subseq fcredit",
669 tpcb->tp_snduna, tpcb->tp_r_subseq,
670 tpcb->tp_fcredit, 0);
671 }
672 #endif
673
674 #ifdef ARGO_DEBUG
675 if (argo_debug[D_ACKSEND]) {
676 printf("Calling ADDOPTION 0x%x, %p, 0x%lx,0x%x\n",
677 TPP_flow_cntl_conf,
678 hdr, (unsigned long)sizeof(bogus), bogus[0]);
679 }
680 #endif
681 ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]);
682 #ifdef ARGO_DEBUG
683 if (argo_debug[D_ACKSEND]) {
684 printf("after ADDOPTION hdr %p hdr->tpdu_li 0x%x\n",
685 hdr, hdr->tpdu_li);
686 printf(
687 "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
688 csum_offset, hdr->tpdu_li);
689 }
690 #endif
691
692 }
693 tpcb->tp_reneged = 0;
694 tpcb->tp_sent_rcvnxt = seq;
695 if (tpcb->tp_fcredit == 0) {
696 int timo = tpcb->tp_keepalive_ticks;
697 if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT)
698 tpcb->tp_rxtshift++;
699 timo = min(timo, ((int) tpcb->tp_dt_ticks) << tpcb->tp_rxtshift);
700 tp_ctimeout(tpcb, TM_sendack, timo);
701 } else
702 tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks);
703 IncStat(ts_AK_sent);
704 IncPStat(tpcb, tps_AK_sent);
705 #ifdef ARGO_DEBUG
706 if (argo_debug[D_ACKSEND]) {
707 printf(
708 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
709 csum_offset, hdr->tpdu_li);
710 }
711 #endif
712 break;
713
714 case ER_TPDU_type:
715 hdr->tpdu_ERreason = eot;
716 hdr->tpdu_cdt = 0;
717 /* no user data */
718 data = (struct mbuf *) 0;
719 IncStat(ts_ER_sent);
720 break;
721 }
722
723 }
724 ASSERT((int) hdr->tpdu_li != 0);
725 #if 0
726 ASSERT((int) hdr->tpdu_li < MLEN);
727 #endif
728
729 m->m_next = data;
730
731 #if 0
732 ASSERT(hdr->tpdu_li < MLEN); /* leave this in */
733 #endif
734 ASSERT(hdr->tpdu_li != 0); /* leave this in */
735
736 m->m_len = hdr->tpdu_li;
737 hdr->tpdu_li--; /* doesn't include the li field */
738
739 datalen = m_datalen(m); /* total len */
740
741 ASSERT(datalen <= tpcb->tp_l_tpdusize); /* may become a problem when
742 * CLNP is used; leave in
743 * here for the time being */
744 #ifdef ARGO_DEBUG
745 if (argo_debug[D_ACKSEND]) {
746 printf(
747 "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n",
748 csum_offset, hdr->tpdu_li);
749 }
750 #endif
751 if (datalen > tpcb->tp_l_tpdusize) {
752 printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n",
753 datalen, tpcb->tp_l_tpdusize);
754 }
755 #ifdef ARGO_DEBUG
756 if (argo_debug[D_EMIT]) {
757 printf(
758 "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n",
759 m->m_len, csum_offset, datalen);
760 }
761 #endif
762 if (tpcb->tp_use_checksum ||
763 (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4))) {
764 iso_gen_csum(m, csum_offset, datalen);
765 }
766 #ifdef ARGO_DEBUG
767 if (argo_debug[D_EMIT]) {
768 printf("tp_emit before tpxxx_output tpcb %p, dutype 0x%x, datalen 0x%x\n",
769 tpcb, dutype, datalen);
770 dump_buf(mtod(m, caddr_t), datalen);
771 }
772 #endif
773
774 #ifdef TP_PERF_MEAS
775 if (DOPERF(tpcb)) {
776 if (dutype == DT_TPDU_type) {
777 PStat(tpcb, Nb_to_ll) += (datalen - m->m_len);
778 tpmeas(tpcb->tp_lref, TPtime_to_ll, NULL,
779 seq, PStat(tpcb, Nb_to_ll),
780 (datalen - m->m_len));
781 }
782 }
783 #endif
784
785 #ifdef TPPT
786 if (tp_traceflags[D_EMIT]) {
787 tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li + 1, datalen, 0);
788 }
789 #endif
790 #ifdef ARGO_DEBUG
791 if (argo_debug[D_EMIT]) {
792 printf("OUTPUT: tpcb %p, isop %p, so %p\n",
793 tpcb, tpcb->tp_npcb, tpcb->tp_sock);
794 }
795 #endif
796
797 {
798 extern char tp_delay;
799
800 if (tp_delay)
801 if (tpcb->tp_use_checksum == 0) {
802 u_int i = tp_delay;
803 for (; i != 0; i--)
804 (void) iso_check_csum(m, datalen);
805 }
806 }
807 ASSERT(m->m_len > 0);
808 error = (tpcb->tp_nlproto->nlp_output) (m, datalen, tpcb->tp_npcb,
809 !tpcb->tp_use_checksum);
810 #ifdef ARGO_DEBUG
811 if (argo_debug[D_EMIT]) {
812 printf("OUTPUT: returned 0x%x\n", error);
813 }
814 #endif
815 #ifdef TPPT
816 if (tp_traceflags[D_EMIT]) {
817 tptraceTPCB(TPPTmisc,
818 "tp_emit nlproto->output netservice returns datalen",
819 tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen);
820 }
821 #endif
822 done:
823 if (error) {
824 if (dutype == AK_TPDU_type)
825 tp_ctimeout(tpcb, TM_sendack, 1);
826 if (error == E_CO_QFULL) {
827 tp_quench((struct inpcb *) tpcb, PRC_QUENCH);
828 return 0;
829 }
830 }
831 return error;
832 }
833 /*
834 * NAME: tp_error_emit()
835 * CALLED FROM: tp_input() when a DR or ER is to be issued in
836 * response to an input error.
837 * FUNCTION and ARGUMENTS:
838 * The error type is the first argument.
839 * The argument (sref) is the source reference on the bad incoming tpdu,
840 * and is used for a destination reference on the outgoing packet.
841 * (faddr) and (laddr) are the foreign and local addresses for this
842 * connection.
843 * (erdata) is a ptr to the errant incoming tpdu, and is copied into the
844 * outgoing ER, if an ER is to be issued.
845 * (erlen) is the number of octets of the errant tpdu that we should
846 * try to copy.
847 * (tpcb) is the pcb that describes the connection for which the bad tpdu
848 * arrived.
849 * RETURN VALUES:
850 * 0 OK
851 * ENOBUFS
852 * E* from net layer datagram output routine
853 * SIDE EFFECTS:
854 *
855 * NOTES:
856 */
857
858 int
859 tp_error_emit(
860 int error,
861 u_long sref,
862 struct sockaddr_iso *faddr,
863 struct sockaddr_iso *laddr,
864 struct mbuf *erdata,
865 int erlen,
866 struct tp_pcb *tpcb,
867 caddr_t cons_channel,
868 int (*dgout_routine)(struct mbuf *, ...))
869 {
870 int dutype;
871 int datalen = 0;
872 struct tpdu *hdr;
873 struct mbuf *m;
874 int csum_offset;
875
876 #ifdef TPPT
877 if (tp_traceflags[D_ERROR_EMIT]) {
878 tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen",
879 error, sref, tpcb, erlen);
880 }
881 #endif
882 #ifdef ARGO_DEBUG
883 if (argo_debug[D_ERROR_EMIT]) {
884 printf(
885 "tp_error_emit error 0x%x sref %lx tpcb %p erlen 0x%x chan %p\n",
886 error, sref, tpcb, erlen, cons_channel);
887 }
888 #endif
889
890 MGET(m, M_DONTWAIT, TPMT_TPHDR);
891 if (m == NULL) {
892 return ENOBUFS;
893 }
894 m->m_len = sizeof(struct tpdu);
895 m->m_nextpkt = NULL;
896
897 hdr = mtod(m, struct tpdu *);
898
899 #ifdef ARGO_DEBUG
900 if (argo_debug[D_ERROR_EMIT]) {
901 printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n",
902 error, error & 0xff, (char) error);
903 }
904 #endif
905
906
907 if (error & TP_ERROR_SNDC)
908 dutype = DC_TPDU_type;
909 else if (error & 0x40) {
910 error &= ~0x40;
911 dutype = ER_TPDU_type;
912 } else
913 dutype = DR_TPDU_type;
914 error &= 0xff;
915
916 hdr->tpdu_type = dutype;
917 hdr->tpdu_cdt = 0;
918
919 switch (dutype) {
920
921 case DC_TPDU_type:
922 IncStat(ts_DC_sent);
923 hdr->tpdu_li = 6;
924 hdr->tpdu_DCdref = htons(sref);
925 hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0;
926 #ifdef ARGO_DEBUG
927 if (argo_debug[D_ERROR_EMIT]) {
928 printf("DC case:\n");
929 dump_buf(hdr, 6);
930 }
931 #endif
932 /* forget the add'l information variable part */
933 break;
934
935 case DR_TPDU_type:
936 IncStat(ts_DR_sent);
937 hdr->tpdu_li = 7;
938 hdr->tpdu_DRdref = htons(sref);
939 hdr->tpdu_DRsref = 0;
940 hdr->tpdu_DRreason = (char) error;
941 #ifdef ARGO_DEBUG
942 if (argo_debug[D_ERROR_EMIT]) {
943 printf("DR case:\n");
944 dump_buf(hdr, 7);
945 }
946 #endif
947 /* forget the add'l information variable part */
948 break;
949
950 case ER_TPDU_type:
951 IncStat(ts_ER_sent);
952 hdr->tpdu_li = 5;
953 hdr->tpdu_ERreason = (char) error;
954 hdr->tpdu_ERdref = htons(sref);
955 break;
956
957 default:
958 ASSERT(0);
959 printf("TP PANIC: bad dutype 0x%x\n", dutype);
960 }
961
962 if (tpcb)
963 if (tpcb->tp_use_checksum) {
964 ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */ );
965 csum_offset = hdr->tpdu_li - 2;
966 }
967 #if 0
968 ASSERT(hdr->tpdu_li < MLEN);
969 #endif
970
971 if (dutype == ER_TPDU_type) {
972 /* copy the errant tpdu into another 'variable part' */
973 caddr_t P;
974
975 #ifdef TPPT
976 if (tp_traceflags[D_ERROR_EMIT]) {
977 tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li,
978 0, 0);
979 }
980 #endif
981 #ifdef ARGO_DEBUG
982 if (argo_debug[D_ERROR_EMIT]) {
983 printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li);
984 }
985 #endif
986
987 /* copy at most as many octets for which you have room */
988 if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN)
989 erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2;
990
991 /* add the "invalid tpdu" parameter : required in class 0 */
992 P = (caddr_t) hdr + (int) (hdr->tpdu_li);
993 vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */
994 vbptr(P)->tpv_len = erlen; /* parameter length */
995 m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */
996
997 /*
998 * tp_input very likely handed us an mbuf chain w/ nothing in
999 * the first mbuf and the data following the empty mbuf
1000 */
1001 if (erdata->m_len == 0) {
1002 erdata = m_free(erdata); /* returns the next mbuf
1003 * on the chain */
1004 }
1005 /*
1006 * copy only up to the bad octet
1007 * (or max that will fit in a header
1008 */
1009 m->m_next = m_copy(erdata, 0, erlen);
1010 hdr->tpdu_li += erlen + 2;
1011 m_freem(erdata);
1012 } else {
1013 #ifdef ARGO_DEBUG
1014 if (argo_debug[D_ERROR_EMIT]) {
1015 printf("error_emit DR error %d tpduli %x\n", error, hdr->tpdu_li);
1016 dump_buf((char *) hdr, hdr->tpdu_li);
1017 }
1018 #endif
1019 m->m_len = hdr->tpdu_li;
1020 m_freem(erdata);
1021 }
1022
1023 hdr->tpdu_li--;
1024 #ifdef TPPT
1025 if (tp_traceflags[D_ERROR_EMIT]) {
1026 tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li + 1, 0, 0);
1027 }
1028 #endif
1029
1030 datalen = m_datalen(m);
1031 if (tpcb) {
1032 if (tpcb->tp_use_checksum) {
1033 #ifdef TPPT
1034 if (tp_traceflags[D_ERROR_EMIT]) {
1035 tptrace(TPPTmisc, "before gen csum datalen", datalen, 0, 0, 0);
1036 }
1037 #endif
1038 #ifdef ARGO_DEBUG
1039 if (argo_debug[D_ERROR_EMIT]) {
1040 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",
1041 datalen, csum_offset);
1042 }
1043 #endif
1044
1045 iso_gen_csum(m, csum_offset, datalen);
1046 }
1047 #ifdef ARGO_DEBUG
1048 if (argo_debug[D_ERROR_EMIT]) {
1049 printf("OUTPUT: tpcb %p, isop %p, so %p\n",
1050 tpcb, tpcb->tp_npcb, tpcb->tp_sock);
1051 }
1052 #endif
1053 }
1054 if (cons_channel) {
1055 #ifdef TPCONS
1056 struct pklcd *lcp = (struct pklcd *) cons_channel;
1057 #ifdef notdef
1058 struct isopcb *isop = (struct isopcb *) lcp->lcd_upnext;
1059 #endif
1060 tpcons_output_dg(m, datalen, cons_channel);
1061 #ifdef notdef
1062 if (tpcb == 0) iso_pcbdetach(isop);
1063 #endif
1064 /*
1065 * but other side may want to try again over same VC, so,
1066 * we'll depend on him closing it, but in case it gets
1067 * forgotten we'll mark it for garbage collection
1068 */
1069 lcp->lcd_flags |= X25_DG_CIRCUIT;
1070 #ifdef ARGO_DEBUG
1071 if (argo_debug[D_ERROR_EMIT]) {
1072 printf("OUTPUT: dutype %#x channel %p\n",
1073 dutype, cons_channel);
1074 }
1075 #endif
1076 #else
1077 printf("TP panic! cons channel %p but not cons configured\n",
1078 cons_channel);
1079 #endif
1080 return 0;
1081 } else if (tpcb) {
1082
1083 #ifdef ARGO_DEBUG
1084 if (argo_debug[D_ERROR_EMIT]) {
1085 printf("tp_error_emit 1 sending DG: Laddr\n");
1086 dump_addr(sisotosa(laddr));
1087 printf("Faddr\n");
1088 dump_addr(sisotosa(faddr));
1089 }
1090 #endif
1091 return (*tpcb->tp_nlproto->nlp_dgoutput) (m, datalen,
1092 &laddr->siso_addr,
1093 &faddr->siso_addr,
1094 /* no route */ (caddr_t) 0, !tpcb->tp_use_checksum);
1095 } else if (dgout_routine) {
1096 #ifdef ARGO_DEBUG
1097 if (argo_debug[D_ERROR_EMIT]) {
1098 printf("tp_error_emit sending DG: Laddr\n");
1099 dump_addr(sisotosa(laddr));
1100 printf("Faddr\n");
1101 dump_addr(sisotosa(faddr));
1102 }
1103 #endif
1104 return (*dgout_routine) (m, datalen, &laddr->siso_addr, &faddr->siso_addr,
1105 (caddr_t) 0, /* nochecksum==false */ 0);
1106 } else {
1107 #ifdef ARGO_DEBUG
1108 if (argo_debug[D_ERROR_EMIT]) {
1109 printf("tp_error_emit DROPPING %p\n", m);
1110 }
1111 #endif
1112 IncStat(ts_send_drop);
1113 m_freem(m);
1114 return 0;
1115 }
1116 }
Cache object: a2cb9cb4ceda1d1e44f8f1e08eeae3ef
|