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