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