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