]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/tp_emit.c
   2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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. 
  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 
  20  * @APPLE_LICENSE_HEADER_END@ 
  23  * Copyright (c) 1991, 1993 
  24  *      The Regents of the University of California.  All rights reserved. 
  26  * Redistribution and use in source and binary forms, with or without 
  27  * modification, are permitted provided that the following conditions 
  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. 
  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 
  54  *      @(#)tp_emit.c   8.1 (Berkeley) 6/10/93 
  57 /*********************************************************** 
  58                 Copyright IBM Corporation 1987 
  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.   
  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 
  78 ******************************************************************/ 
  81  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 
  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. 
  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. 
  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.) 
 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> 
 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> 
 127 #include <netccitt/x25.h> 
 128 #include <netccitt/pk.h> 
 129 #include <netccitt/pk_var.h> 
 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. 
 138 char tp_delay 
= 0x00; /* delay to keep token ring from blowing it */ 
 143  * CALLED FROM: tp.trans and from tp_sbsend() 
 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. 
 156  *      E* returned from net layer output rtn  
 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. 
 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 
 179  *  HOWEVER, we're thinking about putting it in anyway, for 
 180  *  completeness, just like we did with ack subsequencing. 
 184 tp_emit(dutype
, tpcb
, seq
, eot
, data
) 
 191         register struct tpdu 
*hdr
;  
 192         register struct mbuf 
*m
; 
 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. 
 207         "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x", 
 208                 dutype
, tpcb
, eot
, seq
, data
); 
 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
); 
 215                         m
->m_type 
= TPMT_TPHDR
; 
 216                         mbstat
.m_mtypes
[TPMT_TPHDR
]++; 
 218                         m
->m_nextpkt 
= MNULL
; 
 219                         m
->m_data 
= m
->m_pktdat
; 
 220                         m
->m_flags 
= M_PKTHDR
; 
 223                 MGETHDR(m
, M_DONTWAIT
, TPMT_TPHDR
);  
 225         m
->m_data 
+= max_hdr
; 
 227                 if(data 
!= (struct mbuf 
*)0) 
 232         m
->m_len 
= sizeof(struct tpdu
); 
 235         hdr 
= mtod(m
, struct tpdu 
*); 
 236         bzero((caddr_t
)hdr
, sizeof(struct tpdu
)); 
 241                 hdr
->tpdu_type 
= dutype
; 
 242                 hdr
->tpdu_li 
= tp_headersize(dutype
, tpcb
);   
 244                  * class 0 doesn't use this for DT 
 245                  * it'll just get overwritten below  
 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 */); 
 254                                         "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 
 255                                                 csum_offset
, hdr
->tpdu_li
); 
 264                         hdr
->tpdu_CRdref_0 
= 0; /* must be zero */ 
 266                         if (!tpcb
->tp_cebit_off
) { 
 267                                 tpcb
->tp_win_recv 
= tp_start_win 
<< 8; 
 269                                 CONG_INIT_SAMPLE(tpcb
); 
 273 /* Case CC_TPDU_type used to be here */ 
 277                                 hdr
->tpdu_CCsref 
=  htons(tpcb
->tp_lref
); /* same as CRsref */ 
 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
; 
 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
; 
 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); 
 300                                         u_char perf_meas 
= tpcb
->tp_perf_on
; 
 301                                         ADDOPTION(TPP_perf_meas
, hdr
, sizeof(perf_meas
), perf_meas
); 
 304                                 if( dutype 
== CR_TPDU_type 
) { 
 307                                         ASSERT( tpcb
->tp_lsuffixlen 
> 0 ); 
 308                                         ASSERT( tpcb
->tp_fsuffixlen 
> 0 ); 
 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]); 
 318                                 ADDOPTION(TPP_tpdu_size
, hdr
,  
 319                                         sizeof(tpcb
->tp_tpdusize
), tpcb
->tp_tpdusize
); 
 321                                 if (tpcb
->tp_class 
!= TP_CLASS_0
) { 
 322                                         short millisec 
= 500*(tpcb
->tp_sendack_ticks
); 
 324                                         millisec 
= htons(millisec
); 
 325                                         ADDOPTION(TPP_acktime
, hdr
, sizeof(short), millisec
); 
 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
); 
 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
; 
 340                                                         ADDOPTION(TPP_ptpdu_size
, hdr
, 1, size_c
); 
 342                                                         size_s 
= htons(size_s
); 
 343                                                         ADDOPTION(TPP_ptpdu_size
, hdr
, 2, size_s
); 
 348                                 if( (dutype 
== CR_TPDU_type
) && (tpcb
->tp_class 
!= TP_CLASS_0
)){ 
 350                                         ASSERT( 1 == sizeof(tpcb
->tp_vers
) ); 
 351                                         ADDOPTION(TPP_vers
, hdr
, 1, tpcb
->tp_vers
); 
 353                                         /* for each alt protocol class x, 
 355                                          *  option = concat(option, x); 
 356                                          * Well, for now we only have TP0 for an 
 357                                          * alternative so... this is easy. 
 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. 
 364                                         ADDOPTION(TPP_alt_class
, hdr
, 1, x
); 
 367                                 if( hdr
->tpdu_li 
> MLEN
)  
 368                                         panic("tp_emit CR/CC"); 
 373                         if( hdr
->tpdu_DRdref 
== 0 ) { 
 374                                 /* don't issue the DR */ 
 378                         hdr
->tpdu_DRsref 
= htons(tpcb
->tp_lref
); 
 379                         hdr
->tpdu_DRreason 
= (u_char
)eot
; /* WHICH BYTE OF THIS??? */ 
 381                         /* forget the add'l information variable part */ 
 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
); 
 389                         data 
= (struct mbuf 
*)0; 
 393                 case XAK_TPDU_type
: /* xak not used in class 0 */ 
 394                         ASSERT( tpcb
->tp_class 
!= TP_CLASS_0
); /* fall through */ 
 398                                 tptraceTPCB(TPPTXack
, seq
, 0, 0, 0, 0); 
 400                         data 
= (struct mbuf 
*)0; 
 401                         if (tpcb
->tp_xtd_format
) { 
 403                                 union seq_type seqeotX
; 
 407                                 hdr
->tpdu_seqeotX 
= htonl(seqeotX
.s_seqeot
); 
 409                                 hdr
->tpdu_XAKseqX 
= seq
; 
 410 #endif /* BYTE_ORDER */ 
 412                                 hdr
->tpdu_XAKseq 
= seq
; 
 414                         IncStat(ts_XAK_sent
); 
 415                         IncPStat(tpcb
, tps_XAK_sent
); 
 418                 case XPD_TPDU_type
: /* xpd not used in class 0 */ 
 419                         ASSERT( tpcb
->tp_class 
!= TP_CLASS_0
); /* fall through */ 
 421                         if (tpcb
->tp_xtd_format
) { 
 423                                 union seq_type seqeotX
; 
 427                                 hdr
->tpdu_seqeotX 
= htonl(seqeotX
.s_seqeot
); 
 429                                 hdr
->tpdu_XPDseqX 
= seq
; 
 430                                 hdr
->tpdu_XPDeotX 
= 1; /* always 1 for XPD tpdu */ 
 431 #endif /* BYTE_ORDER */ 
 433                                 hdr
->tpdu_XPDseq 
= seq
; 
 434                                 hdr
->tpdu_XPDeot 
= 1; /* always 1 for XPD tpdu */ 
 436                         IncStat(ts_XPD_sent
); 
 437                         IncPStat(tpcb
, tps_XPD_sent
); 
 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"); 
 451                                 tptraceTPCB(TPPTmisc
, "emit DT: eot seq tpdu_li", eot
, seq
,  
 454                         if (tpcb
->tp_xtd_format
) { 
 456                                 union seq_type seqeotX
; 
 460                                 hdr
->tpdu_seqeotX 
= htonl(seqeotX
.s_seqeot
); 
 462                                 hdr
->tpdu_DTseqX 
= seq
; 
 463                                 hdr
->tpdu_DTeotX 
= eot
; 
 464 #endif /* BYTE_ORDER */ 
 465                         } else if (tpcb
->tp_class 
== TP_CLASS_0
) { 
 467                                         printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m
, hdr
); 
 468                                         dump_buf( hdr
, hdr
->tpdu_li 
+ 1 ); 
 470                                 ((struct tp0du 
*)hdr
)->tp0du_eot 
= eot
; 
 471                                 ((struct tp0du 
*)hdr
)->tp0du_mbz 
= 0; 
 473                                         printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m
, hdr
); 
 474                                         dump_buf( hdr
, hdr
->tpdu_li 
+ 1 ); 
 477                                 hdr
->tpdu_DTseq 
= seq
; 
 478                                 hdr
->tpdu_DTeot 
= eot
; 
 481                                 IncStat(ts_EOT_sent
); 
 484                         IncPStat(tpcb
, tps_DT_sent
); 
 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
; 
 492                         if (seq 
!= tpcb
->tp_sent_rcvnxt 
|| tpcb
->tp_rsycnt 
== 0) { 
 493                                 LOCAL_CREDIT( tpcb 
);  
 495                                         SEQ(tpcb
,tpcb
->tp_rcvnxt 
+ tpcb
->tp_lcredit 
-1); 
 496                                 tpcb
->tp_sent_lcdt 
= tpcb
->tp_lcredit
; 
 502                                 /* occasionally fake a reneging so  
 503                                         you can test subsequencing */ 
 505                                         tpcb
->tp_reneged 
= 1; 
 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 
 518                         if( SEQ_LT(tpcb
, tpcb
->tp_sent_uwe
, olduwe
) ) { 
 519                                 tpcb
->tp_reneged 
= 1; 
 520                                 IncStat(ts_lcdt_reduced
); 
 522                                         tptraceTPCB(TPPTmisc
,  
 523                                                 "RENEG: olduwe newuwe lcredit rcvnxt", 
 525                                                 tpcb
->tp_sent_uwe
, tpcb
->tp_lcredit
, 
 530                                 /* new lwe is less than old uwe means we're 
 531                                  * acking before we received a whole window full 
 533                                 if( SEQ_LT( tpcb
, tpcb
->tp_rcvnxt
, olduwe
) ) { 
 534                                         /* tmp1 = number of pkts fewer than the full window */ 
 536                                                 (int) SEQ_SUB( tpcb
, olduwe
, tpcb
->tp_rcvnxt
); 
 540                                         IncPStat( tpcb
,  tps_ack_early
[tmp1
] ); 
 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 
) 
 548                                                         tps_cdt_acked 
[ tmp1 
] 
 549                                                         [ ((tpcb
->tp_lcredit 
> TP_PM_MAX
)? 
 550                                                                 TP_PM_MAX
:tpcb
->tp_lcredit
) ] ); 
 556                                 tptraceTPCB(TPPTack
, seq
, tpcb
->tp_lcredit
, tpcb
->tp_sent_uwe
,  
 557                                         tpcb
->tp_r_subseq
, 0); 
 559                         if (tpcb
->tp_xtd_format
) { 
 561                                 union seq_type seqeotX
; 
 565                                 hdr
->tpdu_seqeotX 
= htonl(seqeotX
.s_seqeot
); 
 566                                 hdr
->tpdu_AKcdtX 
= htons(tpcb
->tp_lcredit
); 
 569                                 hdr
->tpdu_AKseqX 
= seq
; 
 570                                 hdr
->tpdu_AKcdtX 
= tpcb
->tp_lcredit
; 
 571 #endif /* BYTE_ORDER */ 
 573                                 hdr
->tpdu_AKseq 
= seq
; 
 574                                 hdr
->tpdu_AKcdt 
= tpcb
->tp_lcredit
; 
 576                         if ((tpcb
->tp_class 
== TP_CLASS_4
) && 
 577                                 (tpcb
->tp_reneged 
|| acking_ooo
)) { 
 579                                  * Ack subsequence parameter req'd if WE reneged on  
 580                                  * credit offered.  (ISO 8073, 12.2.3.8.2, p. 74) 
 583                                         printf("Adding subseq 0x%x\n", tpcb
->tp_s_subseq
); 
 587                                  * add tmp subseq and do a htons on it. 
 589                                 ADDOPTION(TPP_subseq
, hdr
,  
 590                                         sizeof(tpcb
->tp_s_subseq
), tpcb
->tp_s_subseq
); 
 592                                 tpcb
->tp_s_subseq 
= 0; 
 594                         if ( tpcb
->tp_sendfcc 
|| eot 
) /* overloaded to mean SEND FCC */ { 
 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. 
 615                                  * We send FCC for reasons a) and b) only.  
 616                                  * To add reason c) would require a ridiculous amount of state. 
 619                                 u_short         bogus
[4]; /* lwe(32), subseq(16), cdt(16) */ 
 621                                 u_short         subseq
, fcredit
; 
 623                                 tpcb
->tp_sendfcc 
= 0; 
 625                                 lwe 
= (SeqNum
) htonl(tpcb
->tp_snduna
); 
 626                                 subseq 
= htons(tpcb
->tp_r_subseq
); 
 627                                 fcredit 
= htons(tpcb
->tp_fcredit
); 
 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
)); 
 634                                         tptraceTPCB(TPPTmisc
,  
 635                                                 "emit w/FCC: snduna r_subseq fcredit",  
 636                                                 tpcb
->tp_snduna
, tpcb
->tp_r_subseq
, 
 637                                                 tpcb
->tp_fcredit
, 0); 
 641                                         printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n", 
 643                                                 hdr
, sizeof(bogus
), bogus
[0]); 
 645                                 ADDOPTION(TPP_flow_cntl_conf
, hdr
, sizeof(bogus
), bogus
[0]); 
 647                                         printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n", 
 650                                         "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 
 651                                                         csum_offset
, hdr
->tpdu_li
); 
 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
) 
 661                                 timo 
= min(timo
, ((int)tpcb
->tp_dt_ticks
) << tpcb
->tp_rxtshift
); 
 662                                 tp_ctimeout(tpcb
, TM_sendack
, timo
); 
 664                                 tp_ctimeout(tpcb
, TM_sendack
, tpcb
->tp_keepalive_ticks
); 
 666                         IncPStat(tpcb
, tps_AK_sent
); 
 669                                 "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 
 670                                                 csum_offset
, hdr
->tpdu_li
); 
 675                         hdr
->tpdu_ERreason 
= eot
;  
 678                         data 
= (struct mbuf 
*)0; 
 684         ASSERT( ((int)hdr
->tpdu_li 
> 0) && ((int)hdr
->tpdu_li 
< MLEN
) ); 
 688         ASSERT( hdr
->tpdu_li 
< MLEN 
); /* leave this in */ 
 689         ASSERT( hdr
->tpdu_li 
!= 0 ); /* leave this in */ 
 691         m
->m_len 
= hdr
->tpdu_li 
;  
 692         hdr
->tpdu_li 
--; /* doesn't include the li field */ 
 694         datalen 
= m_datalen( m 
); /* total len */ 
 696         ASSERT( datalen 
<= tpcb
->tp_l_tpdusize 
); /* may become a problem 
 697                                 when CLNP is used; leave in here for the time being */ 
 700                         "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", 
 701                                         csum_offset
, hdr
->tpdu_li
); 
 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
); 
 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
); 
 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
); 
 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
); 
 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
)); 
 732                 tptraceTPCB(TPPTtpduout
, dutype
, hdr
, hdr
->tpdu_li
+1, datalen
, 0); 
 735                 printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", 
 736                         tpcb
,  tpcb
->tp_npcb
,  tpcb
->tp_sock
); 
 739         { extern char tp_delay
; 
 742                         if( tpcb
->tp_use_checksum 
== 0 ) { 
 743                                 register u_int i  
= tp_delay
; 
 745                                         (void) iso_check_csum(m
, datalen
); 
 748         ASSERT( m
->m_len 
> 0 ); 
 749         error 
= (tpcb
->tp_nlproto
->nlp_output
)(tpcb
->tp_npcb
, m
, datalen
, 
 750                 !tpcb
->tp_use_checksum
); 
 752                 printf("OUTPUT: returned 0x%x\n", error
); 
 755                 tptraceTPCB(TPPTmisc
,  
 756                         "tp_emit nlproto->output netservice returns datalen",  
 757                         tpcb
->tp_nlproto
->nlp_output
, tpcb
->tp_netservice
, error
, datalen
);  
 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
); 
 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  
 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 
 784  *              (tpcb) is the pcb that describes the connection for which the bad tpdu 
 789  *      E* from net layer datagram output routine 
 796 tp_error_emit(error
, sref
, faddr
, laddr
, erdata
, erlen
, tpcb
, cons_channel
, 
 800         struct sockaddr_iso 
*faddr
, *laddr
; 
 804         caddr_t                 cons_channel
; 
 805         int                             (*dgout_routine
)(); 
 809         register struct tpdu    
*hdr
;  
 810         register struct mbuf    
*m
; 
 813         IFTRACE(D_ERROR_EMIT
) 
 814                 tptrace(TPPTmisc
, "tp_error_emit error sref tpcb erlen",  
 815                         error
, sref
, tpcb
, erlen
); 
 817         IFDEBUG(D_ERROR_EMIT
) 
 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
); 
 823         MGET(m
, M_DONTWAIT
, TPMT_TPHDR
);  
 827         m
->m_len 
= sizeof(struct tpdu
); 
 830         hdr 
= mtod(m
, struct tpdu 
*); 
 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
); 
 838         if (error 
& TP_ERROR_SNDC
) 
 839                 dutype 
= DC_TPDU_type
; 
 840         else if (error 
& 0x40) { 
 842                 dutype 
= ER_TPDU_type
; 
 844                 dutype 
= DR_TPDU_type
; 
 847         hdr
->tpdu_type 
= dutype
; 
 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"); 
 861                 /* forget the add'l information variable part */ 
 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"); 
 874                 /* forget the add'l information variable part */ 
 880                 hdr
->tpdu_ERreason 
= (char)error
; 
 881                 hdr
->tpdu_ERdref 
= htons(sref
); 
 886                 printf("TP PANIC: bad dutype 0x%x\n", dutype
); 
 890                 if( tpcb
->tp_use_checksum 
) { 
 891                         ADDOPTION(TPP_checksum
, hdr
, 2, csum_offset 
/* dummy argument */);  
 892                         csum_offset 
=  hdr
->tpdu_li 
- 2; 
 895         ASSERT( hdr
->tpdu_li 
< MLEN 
);  
 897         if (dutype 
== ER_TPDU_type
) { 
 898                 /* copy the errant tpdu into another 'variable part' */ 
 901                 IFTRACE(D_ERROR_EMIT
) 
 902                         tptrace(TPPTmisc
, "error_emit ER len tpduli", erlen
, hdr
->tpdu_li
, 
 905                 IFDEBUG(D_ERROR_EMIT
) 
 906                         printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen
, hdr
->tpdu_li
); 
 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; 
 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 */ 
 919                 /* tp_input very likely handed us an mbuf chain w/ nothing in 
 920                  * the first mbuf and the data following the empty mbuf 
 922                 if(erdata
->m_len 
== 0) { 
 923                         erdata 
= m_free(erdata
); /* returns the next mbuf on the chain */ 
 926                  * copy only up to the bad octet 
 927                  * (or max that will fit in a header 
 929                 m
->m_next 
= m_copy(erdata
, 0, erlen
); 
 930                 hdr
->tpdu_li 
+= erlen 
+ 2;  
 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 
); 
 937                 m
->m_len 
= hdr
->tpdu_li 
; 
 942         IFTRACE(D_ERROR_EMIT
) 
 943                 tptrace(TPPTtpduout
, 2, hdr
, hdr
->tpdu_li
+1, 0, 0); 
 946         datalen 
= m_datalen( m
); 
 948                 if( tpcb
->tp_use_checksum 
) { 
 949                         IFTRACE(D_ERROR_EMIT
) 
 950                                 tptrace(TPPTmisc
, "before gen csum datalen", datalen
,0,0,0); 
 952                         IFDEBUG(D_ERROR_EMIT
) 
 953                                 printf("before gen csum datalen 0x%x, csum_offset 0x%x\n",  
 954                                         datalen
, csum_offset
); 
 957                         iso_gen_csum(m
, csum_offset
, datalen
); 
 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
); 
 967                 struct pklcd 
*lcp 
= (struct pklcd 
*)cons_channel
; 
 968                 struct isopcb 
*isop 
= (struct isopcb 
*)lcp
->lcd_upnext
; 
 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
); 
 981                 printf("TP panic! cons channel 0x%x but not cons configured\n", 
 986                 IFDEBUG(D_ERROR_EMIT
) 
 987                         printf("tp_error_emit 1 sending DG: Laddr\n"); 
 988                         dump_addr((struct sockaddr 
*)laddr
); 
 990                         dump_addr((struct sockaddr 
*)faddr
); 
 992                 return (tpcb
->tp_nlproto
->nlp_dgoutput
)( 
 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
); 
1002                                 dump_addr((struct sockaddr 
*)faddr
); 
1004                                 return (*dgout_routine
)( &laddr
->siso_addr
, &faddr
->siso_addr
,  
1005                                         m
, datalen
, /* no route */  
1006                                         (caddr_t
)0, /* nochecksum==false */0); 
1008                         IFDEBUG(D_ERROR_EMIT
) 
1009                                 printf("tp_error_emit DROPPING \n", m
); 
1011                         IncStat(ts_send_drop
);