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