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