diff options
Diffstat (limited to 'sys/netiso')
86 files changed, 31339 insertions, 0 deletions
diff --git a/sys/netiso/argo_debug.h b/sys/netiso/argo_debug.h new file mode 100644 index 0000000..653982f --- /dev/null +++ b/sys/netiso/argo_debug.h @@ -0,0 +1,296 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)argo_debug.h 8.1 (Berkeley) 6/10/93 + */ + +/***************************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: argo_debug.h,v 4.6 88/07/19 15:53:40 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/argo_debug.h,v $ + */ + +#ifndef __ARGO_DEBUG__ +#define __ARGO_DEBUG__ + +#define dump_buf(a, b) Dump_buf((caddr_t)(a), (int)(b)) + +/*********************************************** + * Lint stuff + **********************************************/ +#if defined(lint) +/* + * lint can't handle the flaky vacuous definitions + * of IFDEBUG, ENDDEBUG, etc. + */ +#endif /* defined(lint) */ + +/*********************************************** + * DEBUG ON: + **********************************************/ +#ifndef ARGO_DEBUG +#define ARGO_DEBUG +#endif /* ARGO_DEBUG */ + + +#ifdef ARGO_DEBUG +/* + #ifndef TPPT + #define TPPT + #endif TPPT + + #ifndef TP_PERF_MEAS + #define TP_PERF_MEAS + #endif TP_PERF_MEAS +*/ + +unsigned char argo_debug[128]; + +#define IFDEBUG(ascii) \ + if(argo_debug[ascii]) { +#define ENDDEBUG ; } + +#else /* ARGO_DEBUG */ + +/*********************************************** + * DEBUG OFF: + **********************************************/ + +#ifndef STAR +#define STAR * +#endif /* STAR */ +#define IFDEBUG(ascii) //*beginning of comment*/STAR +#define ENDDEBUG STAR/*end of comment*// + +#endif /* ARGO_DEBUG */ + +/*********************************************** + * ASSERT + **********************************************/ +#ifdef ARGO_DEBUG + +#ifndef lint +#define ASSERT(phrase) \ +if( !(phrase) ) printf("ASSERTION NOT VALID at line %d file %s\n",__LINE__,__FILE__) +#else /* lint */ +#define ASSERT(phrase) /* phrase */ +#endif /* lint */ + +#else /* ARGO_DEBUG */ + +#define ASSERT(phrase) /* phrase */ + +#endif /* ARGO_DEBUG */ + + +/*********************************************** + * CLNP DEBUG OPTIONS + **********************************************/ +#define D_INPUT '\1' +/* clnp input */ +#define D_OUTPUT '\2' +/* clnp output */ +#define D_ROUTE '\3' +/* clnp routing */ +#define D_CTLINPUT '\4' +/* clnp control input */ +#define D_CTLOUTPUT '\5' +/* clnp control output */ +#define D_OPTIONS '\6' +/* clnp options */ +#define D_IOCTL '\7' +/* iso ioctls */ +#define D_ETHER '\10' +/* clnp over ethernet */ +#define D_TOKEN '\11' +/* clnp over token ring */ +#define D_ADCOM '\12' +/* clnp over the adcom */ +#define D_ISO '\13' +/* iso address family */ +#define D_FORWARD '\14' +/* clnp forwarding */ +#define D_DUMPOUT '\15' +/* dump clnp outgoing packets */ +#define D_DUMPIN '\16' +/* dump clnp input packets */ +#define D_DISCARD '\17' +/* debug clnp packet discard/er function */ +#define D_FRAG '\20' +/* clnp fragmentation */ +#define D_REASS '\21' +/* clnp reassembly */ + +char *clnp_iso_addrp(); + +/*********************************************** + * ESIS DEBUG OPTIONS + **********************************************/ +#define D_ESISOUTPUT '\30' +#define D_ESISINPUT '\31' +#define D_SNPA '\32' + +/*********************************************** + * ISIS DEBUG OPTIONS + **********************************************/ +#define D_ISISOUTPUT '\40' +#define D_ISISINPUT '\41' + +/*********************************************** + * EON DEBUG OPTION + **********************************************/ +#define D_EON '\57' + +/*********************************************** + * CONS DEBUG OPTIONS + **********************************************/ + +#define D_ECNWORK '\60' +#define D_ECNOUT '\61' +#define D_ECNFIN '\62' +#define D_ECNDWN '\63' +#define D_ECNUTIL '\64' + +#define D_INCOMING '\70' +#define D_CDATA '\71' +#define D_CFIND '\72' +#define D_CDUMP_REQ '\73' +#define D_CADDR '\74' +#define D_CCONS '\75' +#define D_CCONN '\76' + + +/*********************************************** + * TP DEBUG OPTIONS + **********************************************/ + +#define D_SETPARAMS '\137' +#define D_RTT '\140' + +#define D_ACKRECV '\141' +#define D_ACKSEND '\142' +#define D_CONN '\143' +#define D_CREDIT '\144' +#define D_DATA '\145' +#define D_DRIVER '\146' + +#define D_EMIT '\147' +#define D_ERROR_EMIT '\150' +#define D_TPINPUT '\151' +#define D_INDICATION '\152' +#define D_CHKSUM '\153' + +#define D_RENEG '\154' +#define D_PERF_MEAS '\155' +#define D_MBUF_MEAS '\156' +#define D_RTC '\157' +#define D_SB '\160' + +#define D_DISASTER_CHECK '\161' +#define D_REQUEST '\162' +#define D_STASH '\163' +#define D_NEWSOCK '\164' +#define D_TIMER '\165' + +#define D_TPIOCTL '\166' +#define D_SIZE_CHECK '\167' +#define D_2ER '\170' +#define D_DISASTER_CHECK_W '\171' + +#define D_XPD '\172' +#define D_SYSCALL '\173' +#define D_DROP '\174' +#define D_ZDREF '\175' +#define D_TPISO '\176' +#define D_QUENCH '\177' + +void dump_mbuf(); + +/*********************************************** + * New mbuf types for debugging w/ netstat -m + * This messes up 4.4 malloc for now. need bigger + * mbtypes array for now. + **********************************************/ +#ifdef notdef + +#define TPMT_DATA 0x21 +#define TPMT_RCVRTC 0x42 +#define TPMT_SNDRTC 0x41 +#define TPMT_TPHDR 0x22 +#define TPMT_IPHDR 0x32 +#define TPMT_SONAME 0x28 +#define TPMT_EOT 0x40 +#define TPMT_XPD 0x44 +#define TPMT_PCB 0x23 +#define TPMT_PERF 0x45 + +#else /* ARGO_DEBUG */ + +#define TPMT_DATA MT_DATA +#define TPMT_RCVRTC MT_DATA +#define TPMT_SNDRTC MT_DATA +#define TPMT_IPHDR MT_HEADER +#define TPMT_TPHDR MT_HEADER +#define TPMT_SONAME MT_SONAME +/* MT_EOT and MT_XPD are defined in tp_param.h */ +#define TPMT_XPD MT_OOBDATA +#define TPMT_PCB MT_PCB +#define TPMT_PERF MT_PCB + +#endif /* ARGO_DEBUG */ + +#endif /* __ARGO_DEBUG__ */ diff --git a/sys/netiso/clnl.h b/sys/netiso/clnl.h new file mode 100644 index 0000000..87227dc --- /dev/null +++ b/sys/netiso/clnl.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnl.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +struct clnl_protosw { + int (*clnl_input)(); /* input routine */ +}; diff --git a/sys/netiso/clnp.h b/sys/netiso/clnp.h new file mode 100644 index 0000000..4c81ba3 --- /dev/null +++ b/sys/netiso/clnp.h @@ -0,0 +1,463 @@ +/*- + * Copyright (c) 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp.h 8.2 (Berkeley) 4/16/94 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /big/BSD4.4/isis-usr/src/sys/netiso/RCS/clnp.h,v 1.1 1992/02/07 18:14:59 hagens Exp hagens $ */ +/* $Source: /big/BSD4.4/isis-usr/src/sys/netiso/RCS/clnp.h,v $ */ + +/* should be config option but cpp breaks with too many #defines */ +#define DECBIT + +/* + * Return true if the mbuf is a cluster mbuf + */ +#define IS_CLUSTER(m) ((m)->m_flags & M_EXT) + +/* + * Move the halfword into the two characters + */ +#define HTOC(msb, lsb, hword)\ + (msb) = (u_char)((hword) >> 8);\ + (lsb) = (u_char)((hword) & 0xff) +/* + * Move the two charcters into the halfword + */ +#define CTOH(msb, lsb, hword)\ + (hword) = ((msb) << 8) | (lsb) + +/* + * Return true if the checksum has been set - ie. the checksum is + * not zero + */ +#define CKSUM_REQUIRED(clnp)\ + (((clnp)->cnf_cksum_msb != 0) || ((clnp)->cnf_cksum_lsb != 0)) + +/* + * Fixed part of clnp header + */ +struct clnp_fixed { + u_char cnf_proto_id; /* network layer protocol identifier */ + u_char cnf_hdr_len; /* length indicator (octets) */ + u_char cnf_vers; /* version/protocol identifier extension */ + u_char cnf_ttl; /* lifetime (500 milliseconds) */ + u_char cnf_type; /* type code */ + /* Includes err_ok, more_segs, and seg_ok */ + u_char cnf_seglen_msb; /* pdu segment length (octets) high byte */ + u_char cnf_seglen_lsb; /* pdu segment length (octets) low byte */ + u_char cnf_cksum_msb; /* checksum high byte */ + u_char cnf_cksum_lsb; /* checksum low byte */ +}; +#define CNF_TYPE 0x1f +#define CNF_ERR_OK 0x20 +#define CNF_MORE_SEGS 0x40 +#define CNF_SEG_OK 0x80 + +#define CLNP_CKSUM_OFF 0x07 /* offset of checksum */ + +#define clnl_fixed clnp_fixed + +/* + * Segmentation part of clnp header + */ +struct clnp_segment { + u_short cng_id; /* data unit identifier */ + u_short cng_off; /* segment offset */ + u_short cng_tot_len; /* total length */ +}; + +/* + * Clnp fragment reassembly structures: + * + * All packets undergoing reassembly are linked together in + * clnp_fragl structures. Each clnp_fragl structure contains a + * pointer to the original clnp packet header, as well as a + * list of packet fragments. Each packet fragment + * is headed by a clnp_frag structure. This structure contains the + * offset of the first and last byte of the fragment, as well as + * a pointer to the data (an mbuf chain) of the fragment. + */ + +/* + * NOTE: + * The clnp_frag structure is stored in an mbuf immedately preceeding + * the fragment data. Since there are words in this struct, + * it must be word aligned. + * + * NOTE: + * All the fragment code assumes that the entire clnp header is + * contained in the first mbuf. + */ +struct clnp_frag { + u_int cfr_first; /* offset of first byte of this frag */ + u_int cfr_last; /* offset of last byte of this frag */ + u_int cfr_bytes; /* bytes to shave to get to data */ + struct mbuf *cfr_data; /* ptr to data for this frag */ + struct clnp_frag *cfr_next; /* next fragment in list */ +}; + +struct clnp_fragl { + struct iso_addr cfl_src; /* source of the pkt */ + struct iso_addr cfl_dst; /* destination of the pkt */ + u_short cfl_id; /* id of the pkt */ + u_char cfl_ttl; /* current ttl of pkt */ + u_short cfl_last; /* offset of last byte of packet */ + struct mbuf *cfl_orighdr; /* ptr to original header */ + struct clnp_frag *cfl_frags; /* linked list of fragments for pkt */ + struct clnp_fragl *cfl_next; /* next pkt being reassembled */ +}; + +/* + * The following structure is used to index into an options section + * of a clnp datagram. These values can be used without worry that + * offset or length fields are invalid or too big, etc. That is, + * the consistancy of the options will be guaranteed before this + * structure is filled in. Any pointer (field ending in p) is + * actually the offset from the beginning of the mbuf the option + * is contained in. A value of NULL for any pointer + * means that the option is not present. The length any option + * does not include the option code or option length fields. + */ +struct clnp_optidx { + u_short cni_securep; /* ptr to beginning of security option */ + char cni_secure_len; /* length of entire security option */ + + u_short cni_srcrt_s; /* offset of start of src rt option */ + u_short cni_srcrt_len; /* length of entire src rt option */ + + u_short cni_recrtp; /* ptr to beginning of recrt option */ + char cni_recrt_len; /* length of entire recrt option */ + + char cni_priorp; /* ptr to priority option */ + + u_short cni_qos_formatp; /* ptr to format of qos option */ + char cni_qos_len; /* length of entire qos option */ + + u_char cni_er_reason; /* reason from ER pdu option */ + + /* ESIS options */ + + u_short cni_esct; /* value from ISH ESCT option */ + + u_short cni_netmaskp; /* ptr to beginning of netmask option */ + char cni_netmask_len; /* length of entire netmask option */ + + u_short cni_snpamaskp; /* ptr to beginning of snpamask option */ + char cni_snpamask_len; /* length of entire snpamask option */ + +}; + +#define ER_INVALREAS 0xff /* code for invalid ER pdu discard reason */ + +/* given an mbuf and addr of option, return offset from data of mbuf */ +#define CLNP_OPTTOOFF(m, opt)\ + ((u_short) (opt - mtod(m, caddr_t))) + +/* given an mbuf and offset of option, return address of option */ +#define CLNP_OFFTOOPT(m, off)\ + ((caddr_t) (mtod(m, caddr_t) + off)) + +/* return true iff src route is valid */ +#define CLNPSRCRT_VALID(oidx)\ + ((oidx) && (oidx->cni_srcrt_s)) + +/* return the offset field of the src rt */ +#define CLNPSRCRT_OFF(oidx, options)\ + (*((u_char *)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + 1))) + +/* return the type field of the src rt */ +#define CLNPSRCRT_TYPE(oidx, options)\ + ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s)))) + +/* return the length of the current address */ +#define CLNPSRCRT_CLEN(oidx, options)\ + ((u_char)(*(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options) - 1))) + +/* return the address of the current address */ +#define CLNPSRCRT_CADDR(oidx, options)\ + ((caddr_t)(CLNP_OFFTOOPT(options, oidx->cni_srcrt_s) + CLNPSRCRT_OFF(oidx, options))) + +/* + * return true if the src route has run out of routes + * this is true if the offset of next route is greater than the end of the rt + */ +#define CLNPSRCRT_TERM(oidx, options)\ + (CLNPSRCRT_OFF(oidx, options) > oidx->cni_srcrt_len) + +/* + * Options a user can set/get + */ +#define CLNPOPT_FLAGS 0x01 /* flags: seg permitted, no er xmit, etc */ +#define CLNPOPT_OPTS 0x02 /* datagram options */ + +/* + * Values for particular datagram options + */ +#define CLNPOVAL_PAD 0xcc /* padding */ +#define CLNPOVAL_SECURE 0xc5 /* security */ +#define CLNPOVAL_SRCRT 0xc8 /* source routing */ +#define CLNPOVAL_RECRT 0xcb /* record route */ +#define CLNPOVAL_QOS 0xc3 /* quality of service */ +#define CLNPOVAL_PRIOR 0xcd /* priority */ +#define CLNPOVAL_ERREAS 0xc1 /* ER PDU ONLY: reason for discard */ + +#define CLNPOVAL_SRCSPEC 0x40 /* source address specific */ +#define CLNPOVAL_DSTSPEC 0x80 /* destination address specific */ +#define CLNPOVAL_GLOBAL 0xc0 /* globally unique */ + +/* Globally Unique QOS */ +#define CLNPOVAL_SEQUENCING 0x10 /* sequencing preferred */ +#define CLNPOVAL_CONGESTED 0x08 /* congestion experienced */ +#define CLNPOVAL_LOWDELAY 0x04 /* low transit delay */ + +#define CLNPOVAL_PARTRT 0x00 /* partial source routing */ +#define CLNPOVAL_COMPRT 0x01 /* complete source routing */ + +/* + * Clnp flags used in a control block flags field. + * NOTE: these must be out of the range of bits defined in ../net/raw_cb.h + */ +#define CLNP_NO_SEG 0x010 /* segmentation not permitted */ +#define CLNP_NO_ER 0x020 /* do not generate ERs */ +#define CLNP_SEND_RAW 0x080 /* send pkt as RAW DT rather than TP DT */ +#define CLNP_NO_CKSUM 0x100 /* don't use clnp checksum */ +#define CLNP_ECHO 0x200 /* send echo request */ +#define CLNP_NOCACHE 0x400 /* don't store cache information */ +#define CLNP_ECHOR 0x800 /* send echo reply */ + +/* valid clnp flags */ +#define CLNP_VFLAGS (CLNP_SEND_RAW|CLNP_NO_SEG|CLNP_NO_ER|CLNP_NO_CKSUM\ + |CLNP_ECHO|CLNP_NOCACHE|CLNP_ECHOR) + +/* + * Constants used by clnp + */ +#define CLNP_HDR_MIN (sizeof (struct clnp_fixed)) +#define CLNP_HDR_MAX (254) +#define CLNP_TTL_UNITS 2 /* 500 milliseconds */ +#define CLNP_TTL 15*CLNP_TTL_UNITS /* time to live (seconds) */ +#define ISO8473_V1 0x01 + +/* + * Clnp packet types + * In order to test raw clnp and tp/clnp simultaneously, a third type of + * packet has been defined: CLNP_RAW. This is done so that the input + * routine can switch to the correct input routine (rclnp_input or + * tpclnp_input) based on the type field. If clnp had a higher level protocol + * field, this would not be necessary. + */ +#define CLNP_DT 0x1C /* normal data */ +#define CLNP_ER 0x01 /* error report */ +#define CLNP_RAW 0x1D /* debug only */ +#define CLNP_EC 0x1E /* echo packet */ +#define CLNP_ECR 0x1F /* echo reply */ + +/* + * ER pdu error codes + */ +#define GEN_NOREAS 0x00 /* reason not specified */ +#define GEN_PROTOERR 0x01 /* protocol procedure error */ +#define GEN_BADCSUM 0x02 /* incorrect checksum */ +#define GEN_CONGEST 0x03 /* pdu discarded due to congestion */ +#define GEN_HDRSYNTAX 0x04 /* header syntax error */ +#define GEN_SEGNEEDED 0x05 /* segmentation needed, but not permitted */ +#define GEN_INCOMPLETE 0x06 /* incomplete pdu received */ +#define GEN_DUPOPT 0x07 /* duplicate option */ + +/* address errors */ +#define ADDR_DESTUNREACH 0x80 /* destination address unreachable */ +#define ADDR_DESTUNKNOWN 0x81 /* destination address unknown */ + +/* source routing */ +#define SRCRT_UNSPECERR 0x90 /* unspecified src rt error */ +#define SRCRT_SYNTAX 0x91 /* syntax error in src rt field */ +#define SRCRT_UNKNOWNADDR 0x92 /* unknown addr in src rt field */ +#define SRCRT_BADPATH 0x93 /* path not acceptable */ + +/* lifetime */ +#define TTL_EXPTRANSIT 0xa0 /* lifetime expired during transit */ +#define TTL_EXPREASS 0xa1 /* lifetime expired during reassembly */ + +/* pdu discarded */ +#define DISC_UNSUPPOPT 0xb0 /* unsupported option not specified? */ +#define DISC_UNSUPPVERS 0xb1 /* unsupported protocol version */ +#define DISC_UNSUPPSECURE 0xb2 /* unsupported security option */ +#define DISC_UNSUPPSRCRT 0xb3 /* unsupported src rt option */ +#define DISC_UNSUPPRECRT 0xb4 /* unsupported rec rt option */ + +/* reassembly */ +#define REASS_INTERFERE 0xc0 /* reassembly interference */ +#define CLNP_ERRORS 22 + + +#ifdef KERNEL +int clnp_er_index(); +#endif + +#ifdef CLNP_ER_CODES +u_char clnp_er_codes[CLNP_ERRORS] = { +GEN_NOREAS, GEN_PROTOERR, GEN_BADCSUM, GEN_CONGEST, +GEN_HDRSYNTAX, GEN_SEGNEEDED, GEN_INCOMPLETE, GEN_DUPOPT, +ADDR_DESTUNREACH, ADDR_DESTUNKNOWN, +SRCRT_UNSPECERR, SRCRT_SYNTAX, SRCRT_UNKNOWNADDR, SRCRT_BADPATH, +TTL_EXPTRANSIT, TTL_EXPREASS, +DISC_UNSUPPOPT, DISC_UNSUPPVERS, DISC_UNSUPPSECURE, +DISC_UNSUPPSRCRT, DISC_UNSUPPRECRT, REASS_INTERFERE }; +#endif + +#ifdef TROLL + +#define TR_DUPEND 0x01 /* duplicate end of fragment */ +#define TR_DUPPKT 0x02 /* duplicate entire packet */ +#define TR_DROPPKT 0x04 /* drop packet on output */ +#define TR_TRIM 0x08 /* trim bytes from packet */ +#define TR_CHANGE 0x10 /* change bytes in packet */ +#define TR_MTU 0x20 /* delta to change device mtu */ +#define TR_CHUCK 0x40 /* drop packet in rclnp_input */ +#define TR_BLAST 0x80 /* force rclnp_output to blast many packet */ +#define TR_RAWLOOP 0x100 /* make if_loop call clnpintr directly */ +struct troll { + int tr_ops; /* operations to perform */ + float tr_dup_size; /* % to duplicate */ + float tr_dup_freq; /* frequency to duplicate packets */ + float tr_drop_freq; /* frequence to drop packets */ + int tr_mtu_adj; /* delta to adjust if mtu */ + int tr_blast_cnt; /* # of pkts to blast out */ +}; + +#define SN_OUTPUT(clcp, m)\ + troll_output(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) + +#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ + rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))\ + - trollctl.tr_mtu_adj) + +#ifdef KERNEL +extern float troll_random; +#endif + +#else /* NO TROLL */ + +#define SN_OUTPUT(clcp, m)\ + (*clcp->clc_ifp->if_output)(clcp->clc_ifp, m, clcp->clc_firsthop, clcp->clc_rt) + +#define SN_MTU(ifp, rt) (((rt && rt->rt_rmx.rmx_mtu) ?\ + rt->rt_rmx.rmx_mtu : clnp_badmtu(ifp, rt, __LINE__, __FILE__))) + +#endif /* TROLL */ + +/* + * Macro to remove an address from a clnp header + */ +#define CLNP_EXTRACT_ADDR(isoa, hoff, hend)\ + {\ + isoa.isoa_len = (u_char)*hoff;\ + if ((((++hoff) + isoa.isoa_len) > hend) ||\ + (isoa.isoa_len > 20) || (isoa.isoa_len == 0)) {\ + hoff = (caddr_t)0;\ + } else {\ + (void) bcopy(hoff, (caddr_t)isoa.isoa_genaddr, isoa.isoa_len);\ + hoff += isoa.isoa_len;\ + }\ + } + +/* + * Macro to insert an address into a clnp header + */ +#define CLNP_INSERT_ADDR(hoff, isoa)\ + *hoff++ = (isoa).isoa_len;\ + (void) bcopy((caddr_t)((isoa).isoa_genaddr), hoff, (isoa).isoa_len);\ + hoff += (isoa).isoa_len; + +/* + * Clnp hdr cache. Whenever a clnp packet is sent, a copy of the + * header is made and kept in this cache. In addition to a copy of + * the cached clnp hdr, the cache contains + * information necessary to determine whether the new packet + * to send requires a new header to be built. + */ +struct clnp_cache { + /* these fields are used to check the validity of the cache */ + struct iso_addr clc_dst; /* destination of packet */ + struct mbuf *clc_options; /* ptr to options mbuf */ + int clc_flags; /* flags passed to clnp_output */ + + /* these fields are state that clnp_output requires to finish the pkt */ + int clc_segoff; /* offset of seg part of header */ + struct rtentry *clc_rt; /* ptr to rtentry (points into + the route structure) */ + struct sockaddr *clc_firsthop; /* first hop of packet */ + struct ifnet *clc_ifp; /* ptr to interface structure */ + struct iso_ifaddr *clc_ifa; /* ptr to interface address */ + struct mbuf *clc_hdr; /* cached pkt hdr (finally)! */ +}; + +#ifndef satosiso +#define satosiso(sa)\ + ((struct sockaddr_iso *)(sa)) +#endif + +#ifdef KERNEL +caddr_t clnp_insert_addr(); +struct iso_addr *clnp_srcaddr(); +struct mbuf *clnp_reass(); +#ifdef TROLL +struct troll trollctl; +#endif /* TROLL */ +#endif /* KERNEL */ diff --git a/sys/netiso/clnp_debug.c b/sys/netiso/clnp_debug.c new file mode 100644 index 0000000..964638e --- /dev/null +++ b/sys/netiso/clnp_debug.c @@ -0,0 +1,260 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_debug.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: clnp_debug.c,v 4.2 88/06/29 14:58:34 hagens Exp $ */ +/* $Source: /usr/argo/sys/netargo/RCS/clnp_debug.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +#ifdef ARGO_DEBUG + +#ifdef TESTDEBUG +#ifdef notdef +struct addr_37 u_37 = { + {0x00, 0x02, 0x00, 0x10, 0x20, 0x30, 0x35}, + {0x01, 0x02, 0x03, 0x04, 0x50, 0x60, 0x70, 0x80, 0x90} +}; +struct addr_osinet u_osinet = { + {0x00, 0x04}, + {0x00, 0x02, 0x00, 0x01, 0x23, 0x42, 0x78, 0x20, 0x01, 0x05, 0x00} +}; +#endif /* notdef */ +struct addr_rfc986 u_rfc986 = { + {0x00, 0x06}, + {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11} +}; +struct addr_rfc986 u_bad = { + {0x00, 0x01}, + {0x01, 0xc0, 0x0c, 0x0c, 0xab, 0x11} +}; +#include <stdio.h> +main() +{ + struct iso_addr a; + + a.isoa_afi = AFI_37; + a.isoa_u.addr_37 = u_37; + a.isoa_len = 17; + printf("type 37: %s\n", clnp_iso_addrp(&a)); + + a.isoa_afi = AFI_OSINET; + a.isoa_u.addr_osinet = u_osinet; + a.isoa_len = 14; + printf("type osinet: %s\n", clnp_iso_addrp(&a)); + + a.isoa_afi = AFI_RFC986; + a.isoa_u.addr_rfc986 = u_rfc986; + a.isoa_len = 9; + printf("type rfc986: %s\n", clnp_iso_addrp(&a)); + + a.isoa_afi = 12; + a.isoa_u.addr_rfc986 = u_rfc986; + a.isoa_len = 9; + printf("type bad afi: %s\n", clnp_iso_addrp(&a)); + + a.isoa_afi = AFI_RFC986; + a.isoa_u.addr_rfc986 = u_bad; + a.isoa_len = 9; + printf("type bad idi: %s\n", clnp_iso_addrp(&a)); +} +#endif /* TESTDEBUG */ + +unsigned int clnp_debug; +static char letters[] = "0123456789abcdef"; + +/* + * Print buffer in hex, return addr of where we left off. + * Do not null terminate. + */ +char * +clnp_hexp(src, len, where) +char *src; /* src of data to print */ +int len; /* lengthof src */ +char *where; /* where to put data */ +{ + int i; + + for (i=0; i<len; i++) { + register int j = ((u_char *)src)[i]; + *where++ = letters[j >> 4]; + *where++ = letters[j & 0x0f]; + } + return where; +} + +/* + * Return a ptr to a human readable form of an iso addr + */ +static char iso_addr_b[50]; +#define DELIM '.'; + +char * +clnp_iso_addrp(isoa) +struct iso_addr *isoa; +{ + char *cp; + + /* print length */ + sprintf(iso_addr_b, "[%d] ", isoa->isoa_len); + + /* set cp to end of what we have */ + cp = iso_addr_b; + while (*cp) + cp++; + + /* print afi */ + cp = clnp_hexp(isoa->isoa_genaddr, (int)isoa->isoa_len, cp); +#ifdef notdef + *cp++ = DELIM; + + /* print type specific part */ + switch(isoa->isoa_afi) { + case AFI_37: + cp = clnp_hexp(isoa->t37_idi, ADDR37_IDI_LEN, cp); + *cp++ = DELIM; + cp = clnp_hexp(isoa->t37_dsp, ADDR37_DSP_LEN, cp); + break; + +/* case AFI_OSINET:*/ + case AFI_RFC986: { + u_short idi; + + /* osinet and rfc986 have idi in the same place */ + /* print idi */ + cp = clnp_hexp(isoa->rfc986_idi, ADDROSINET_IDI_LEN, cp); + *cp++ = DELIM; + CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi); + + if (idi == IDI_OSINET) { + struct ovl_osinet *oosi = (struct ovl_osinet *)isoa; + cp = clnp_hexp(oosi->oosi_orgid, OVLOSINET_ORGID_LEN, cp); + *cp++ = DELIM; + cp = clnp_hexp(oosi->oosi_snetid, OVLOSINET_SNETID_LEN, cp); + *cp++ = DELIM; + cp = clnp_hexp(oosi->oosi_snpa, OVLOSINET_SNPA_LEN, cp); + *cp++ = DELIM; + cp = clnp_hexp(oosi->oosi_nsap, OVLOSINET_NSAP_LEN, cp); + } else if (idi == IDI_RFC986) { + struct ovl_rfc986 *o986 = (struct ovl_rfc986 *)isoa; + cp = clnp_hexp(&o986->o986_vers, 1, cp); + *cp++ = DELIM; +#ifdef vax + sprintf(cp, "%d.%d.%d.%d.%d", + o986->o986_inetaddr[0] & 0xff, + o986->o986_inetaddr[1] & 0xff, + o986->o986_inetaddr[2] & 0xff, + o986->o986_inetaddr[3] & 0xff, + o986->o986_upid & 0xff); + return(iso_addr_b); +#else + cp = clnp_hexp(&o986->o986_inetaddr[0], 1, cp); + *cp++ = DELIM; + cp = clnp_hexp(&o986->o986_inetaddr[1], 1, cp); + *cp++ = DELIM; + cp = clnp_hexp(&o986->o986_inetaddr[2], 1, cp); + *cp++ = DELIM; + cp = clnp_hexp(&o986->o986_inetaddr[3], 1, cp); + *cp++ = DELIM; + cp = clnp_hexp(&o986->o986_upid, 1, cp); +#endif /* vax */ + } + + } break; + + default: + *cp++ = '?'; + break; + } +#endif /* notdef */ + *cp = (char)0; + + return(iso_addr_b); +} + +char * +clnp_saddr_isop(s) +register struct sockaddr_iso *s; +{ + register char *cp = clnp_iso_addrp(&s->siso_addr); + + while (*cp) cp++; + *cp++ = '('; + cp = clnp_hexp(TSEL(s), (int)s->siso_tlen, cp); + *cp++ = ')'; + *cp++ = 0; + return (iso_addr_b); +} + +#endif /* ARGO_DEBUG */ diff --git a/sys/netiso/clnp_er.c b/sys/netiso/clnp_er.c new file mode 100644 index 0000000..8b7f45b --- /dev/null +++ b/sys/netiso/clnp_er.c @@ -0,0 +1,375 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_er.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_er.c,v 5.1 89/02/09 16:20:18 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_er.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_pcb.h> +#define CLNP_ER_CODES +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +static struct clnp_fixed er_template = { + ISO8473_CLNP, /* network identifier */ + 0, /* length */ + ISO8473_V1, /* version */ + CLNP_TTL, /* ttl */ + CLNP_ER, /* type */ + 0, /* segment length */ + 0 /* checksum */ +}; + +/* + * FUNCTION: clnp_er_input + * + * PURPOSE: Process an ER pdu. + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_er_input(m, src, reason) +struct mbuf *m; /* ptr to packet itself */ +struct iso_addr *src; /* ptr to src of er */ +u_char reason; /* reason code of er */ +{ + int cmd = -1; + extern u_char clnp_protox[]; + + IFDEBUG(D_CTLINPUT) + printf("clnp_er_input: m x%x, src %s, reason x%x\n", m, + clnp_iso_addrp(src), reason); + ENDDEBUG + + INCSTAT(cns_er_inhist[clnp_er_index(reason)]); + switch (reason) { + case GEN_NOREAS: + case GEN_PROTOERR: + break; + case GEN_BADCSUM: + cmd = PRC_PARAMPROB; + break; + case GEN_CONGEST: + cmd = PRC_QUENCH; + break; + case GEN_HDRSYNTAX: + cmd = PRC_PARAMPROB; + break; + case GEN_SEGNEEDED: + cmd = PRC_MSGSIZE; + break; + case GEN_INCOMPLETE: + cmd = PRC_PARAMPROB; + break; + case GEN_DUPOPT: + cmd = PRC_PARAMPROB; + break; + case ADDR_DESTUNREACH: + cmd = PRC_UNREACH_HOST; + break; + case ADDR_DESTUNKNOWN: + cmd = PRC_UNREACH_PROTOCOL; + break; + case SRCRT_UNSPECERR: + case SRCRT_SYNTAX: + case SRCRT_UNKNOWNADDR: + case SRCRT_BADPATH: + cmd = PRC_UNREACH_SRCFAIL; + break; + case TTL_EXPTRANSIT: + cmd = PRC_TIMXCEED_INTRANS; + break; + case TTL_EXPREASS: + cmd = PRC_TIMXCEED_REASS; + break; + case DISC_UNSUPPOPT: + case DISC_UNSUPPVERS: + case DISC_UNSUPPSECURE: + case DISC_UNSUPPSRCRT: + case DISC_UNSUPPRECRT: + cmd = PRC_PARAMPROB; + break; + case REASS_INTERFERE: + cmd = PRC_TIMXCEED_REASS; + break; + } + + /* + * tpclnp_ctlinput1 is called directly so that we don't + * have to build an iso_sockaddr out of src. + */ + if (cmd >= 0) + tpclnp_ctlinput1(cmd, src); + + m_freem(m); +} + +/* + * FUNCTION: clnp_discard + * + * PURPOSE: Discard a clnp datagram + * + * RETURNS: nothing + * + * SIDE EFFECTS: Will emit an ER pdu if possible + * + * NOTES: This code assumes that we have previously tried to pull + * up the header of the datagram into one mbuf. + */ +clnp_discard(m, reason) +struct mbuf *m; /* header of packet to discard */ +char reason; /* reason for discard */ +{ + IFDEBUG(D_DISCARD) + printf("clnp_discard: m x%x, reason x%x\n", m, reason); + ENDDEBUG + + if (m != NULL) { + if (m->m_len >= sizeof(struct clnp_fixed)) { + register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); + + if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && + (clnp->cnf_type & CNF_ERR_OK)) { + clnp_emit_er(m, reason); + return; + } + } + m_freem(m); + } +} + +/* + * FUNCTION: clnp_emit_er + * + * PURPOSE: Send an ER pdu. + * The src of the of the ER pdu is the host that is sending + * the ER (ie. us), *not* the original destination of the + * packet. + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: Takes responsibility for freeing mbuf passed + * This function may be called with a packet that + * was created by us; in this case, do not send + * an ER. + */ +clnp_emit_er(m, reason) +struct mbuf *m; /* header of packet to discard */ +char reason; /* reason for discard */ +{ + register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); + register struct clnp_fixed *er; + struct route_iso route; + struct ifnet *ifp; + struct sockaddr *first_hop; + struct iso_addr src, dst, *our_addr; + caddr_t hoff, hend; + int total_len; /* total len of dg */ + struct mbuf *m0; /* contains er pdu hdr */ + struct iso_ifaddr *ia = 0; + + IFDEBUG(D_DISCARD) + printf("clnp_emit_er: m x%x, hdr len %d\n", m, clnp->cnf_hdr_len); + ENDDEBUG + + bzero((caddr_t)&route, sizeof(route)); + + /* + * If header length is incorrect, or entire header is not contained + * in this mbuf, we punt + */ + if ((clnp->cnf_hdr_len < CLNP_HDR_MIN) || + (clnp->cnf_hdr_len > CLNP_HDR_MAX) || + (clnp->cnf_hdr_len > m->m_len)) + goto bad; + + /* extract src, dest address */ + hend = (caddr_t)clnp + clnp->cnf_hdr_len; + hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); + CLNP_EXTRACT_ADDR(dst, hoff, hend); + if (hoff == (caddr_t)0) { + goto bad; + } + CLNP_EXTRACT_ADDR(src, hoff, hend); + if (hoff == (caddr_t)0) { + goto bad; + } + + /* + * Do not send ER if we generated the packet. + */ + if (clnp_ours(&src)) + goto bad; + + /* + * Trim mbuf to hold only the header. + * This mbuf will be the 'data' of the er pdu + */ + if (m->m_next != NULL) { + m_freem(m->m_next); + m->m_next = NULL; + } + + if (m->m_len > clnp->cnf_hdr_len) + m_adj(m, (int)-(m->m_len - (int)clnp->cnf_hdr_len)); + + /* route er pdu: note we send pkt to src of original packet */ + if (clnp_route(&src, &route, /* flags */0, &first_hop, &ia) != 0) + goto bad; + + /* compute our address based upon firsthop/ifp */ + if (ia) + our_addr = &ia->ia_addr.siso_addr; + else + goto bad; + ifp = ia->ia_ifp; + + IFDEBUG(D_DISCARD) + printf("clnp_emit_er: to %s", clnp_iso_addrp(&src)); + printf(" from %s\n", clnp_iso_addrp(our_addr)); + ENDDEBUG + + IFDEBUG(D_DISCARD) + printf("clnp_emit_er: packet routed to %s\n", + clnp_iso_addrp(&((struct sockaddr_iso *)first_hop)->siso_addr)); + ENDDEBUG + + /* allocate mbuf for er pdu header: punt on no space */ + MGET(m0, M_DONTWAIT, MT_HEADER); + if (m0 == 0) + goto bad; + + m0->m_next = m; + er = mtod(m0, struct clnp_fixed *); + *er = er_template; + + /* setup src/dst on er pdu */ + /* NOTE REVERSAL OF SRC/DST */ + hoff = (caddr_t)er + sizeof(struct clnp_fixed); + CLNP_INSERT_ADDR(hoff, src); + CLNP_INSERT_ADDR(hoff, *our_addr); + + /* + * TODO: if complete src rt was specified, then reverse path, and + * copy into er as option. + */ + + /* add er option */ + *hoff++ = CLNPOVAL_ERREAS; /* code */ + *hoff++ = 2; /* length */ + *hoff++ = reason; /* discard reason */ + *hoff++ = 0; /* error localization = not specified */ + + /* set length */ + er->cnf_hdr_len = m0->m_len = (u_char)(hoff - (caddr_t)er); + total_len = m0->m_len + m->m_len; + HTOC(er->cnf_seglen_msb, er->cnf_seglen_lsb, total_len); + + /* compute checksum (on header only) */ + iso_gen_csum(m0, CLNP_CKSUM_OFF, (int)er->cnf_hdr_len); + + /* trim packet if too large for interface */ + if (total_len > ifp->if_mtu) + m_adj(m0, -(total_len - ifp->if_mtu)); + + /* send packet */ + INCSTAT(cns_er_outhist[clnp_er_index(reason)]); + (void) (*ifp->if_output)(ifp, m0, first_hop, route.ro_rt); + goto done; + +bad: + m_freem(m); + +done: + /* free route if it is a temp */ + if (route.ro_rt != NULL) + RTFREE(route.ro_rt); +} + +clnp_er_index(p) +u_char p; +{ + register u_char *cp = clnp_er_codes + CLNP_ERRORS; + while (cp > clnp_er_codes) { + cp--; + if (*cp == p) + return (cp - clnp_er_codes); + } + return (CLNP_ERRORS + 1); +} diff --git a/sys/netiso/clnp_frag.c b/sys/netiso/clnp_frag.c new file mode 100644 index 0000000..546a592 --- /dev/null +++ b/sys/netiso/clnp_frag.c @@ -0,0 +1,859 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_frag.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_frag.c,v 5.1 89/02/09 16:20:26 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_frag.c,v $ */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +/* all fragments are hung off this list */ +struct clnp_fragl *clnp_frags = NULL; + +struct mbuf *clnp_comp_pdu(); + + +/* + * FUNCTION: clnp_fragment + * + * PURPOSE: Fragment a datagram, and send the itty bitty pieces + * out over an interface. + * + * RETURNS: success - 0 + * failure - unix error code + * + * SIDE EFFECTS: + * + * NOTES: If there is an error sending the packet, clnp_discard + * is called to discard the packet and send an ER. If + * clnp_fragment was called from clnp_output, then + * we generated the packet, and should not send an + * ER -- clnp_emit_er will check for this. Otherwise, + * the packet was fragmented during forwarding. In this + * case, we ought to send an ER back. + */ +clnp_fragment(ifp, m, first_hop, total_len, segoff, flags, rt) +struct ifnet *ifp; /* ptr to outgoing interface */ +struct mbuf *m; /* ptr to packet */ +struct sockaddr *first_hop; /* ptr to first hop */ +int total_len; /* length of datagram */ +int segoff; /* offset of segpart in hdr */ +int flags; /* flags passed to clnp_output */ +struct rtentry *rt; /* route if direct ether */ +{ + struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); + int hdr_len = (int)clnp->cnf_hdr_len; + int frag_size = (SN_MTU(ifp, rt) - hdr_len) & ~7; + + total_len -= hdr_len; + if ((clnp->cnf_type & CNF_SEG_OK) && + (total_len >= 8) && + (frag_size > 8 || (frag_size == 8 && !(total_len & 7)))) { + + struct mbuf *hdr = NULL; /* save copy of clnp hdr */ + struct mbuf *frag_hdr = NULL; + struct mbuf *frag_data = NULL; + struct clnp_segment seg_part; /* segmentation header */ + int frag_base; + int error = 0; + + + INCSTAT(cns_fragmented); + (void) bcopy(segoff + mtod(m, caddr_t), (caddr_t)&seg_part, + sizeof(seg_part)); + frag_base = ntohs(seg_part.cng_off); + /* + * Duplicate header, and remove from packet + */ + if ((hdr = m_copy(m, 0, hdr_len)) == NULL) { + clnp_discard(m, GEN_CONGEST); + return(ENOBUFS); + } + m_adj(m, hdr_len); + + while (total_len > 0) { + int remaining, last_frag; + + IFDEBUG(D_FRAG) + struct mbuf *mdump = frag_hdr; + int tot_mlen = 0; + printf("clnp_fragment: total_len %d:\n", total_len); + while (mdump != NULL) { + printf("\tmbuf x%x, m_len %d\n", + mdump, mdump->m_len); + tot_mlen += mdump->m_len; + mdump = mdump->m_next; + } + printf("clnp_fragment: sum of mbuf chain %d:\n", tot_mlen); + ENDDEBUG + + frag_size = min(total_len, frag_size); + if ((remaining = total_len - frag_size) == 0) + last_frag = 1; + else { + /* + * If this fragment will cause the last one to + * be less than 8 bytes, shorten this fragment a bit. + * The obscure test on frag_size above ensures that + * frag_size will be positive. + */ + last_frag = 0; + if (remaining < 8) + frag_size -= 8; + } + + + IFDEBUG(D_FRAG) + printf("clnp_fragment: seg off %d, size %d, remaining %d\n", + ntohs(seg_part.cng_off), frag_size, total_len-frag_size); + if (last_frag) + printf("clnp_fragment: last fragment\n"); + ENDDEBUG + + if (last_frag) { + /* + * this is the last fragment; we don't need to get any other + * mbufs. + */ + frag_hdr = hdr; + frag_data = m; + } else { + /* duplicate header and data mbufs */ + if ((frag_hdr = m_copy(hdr, 0, (int)M_COPYALL)) == NULL) { + clnp_discard(hdr, GEN_CONGEST); + m_freem(m); + return(ENOBUFS); + } + if ((frag_data = m_copy(m, 0, frag_size)) == NULL) { + clnp_discard(hdr, GEN_CONGEST); + m_freem(m); + m_freem(frag_hdr); + return(ENOBUFS); + } + INCSTAT(cns_fragments); + } + clnp = mtod(frag_hdr, struct clnp_fixed *); + + if (!last_frag) + clnp->cnf_type |= CNF_MORE_SEGS; + + /* link together */ + m_cat(frag_hdr, frag_data); + + /* insert segmentation part; updated below */ + bcopy((caddr_t)&seg_part, mtod(frag_hdr, caddr_t) + segoff, + sizeof(struct clnp_segment)); + + { + int derived_len = hdr_len + frag_size; + HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, derived_len); + if ((frag_hdr->m_flags & M_PKTHDR) == 0) + panic("clnp_frag:lost header"); + frag_hdr->m_pkthdr.len = derived_len; + } + /* compute clnp checksum (on header only) */ + if (flags & CLNP_NO_CKSUM) { + HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); + } else { + iso_gen_csum(frag_hdr, CLNP_CKSUM_OFF, hdr_len); + } + + IFDEBUG(D_DUMPOUT) + struct mbuf *mdump = frag_hdr; + printf("clnp_fragment: sending dg:\n"); + while (mdump != NULL) { + printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); + mdump = mdump->m_next; + } + ENDDEBUG + +#ifdef TROLL + error = troll_output(ifp, frag_hdr, first_hop, rt); +#else + error = (*ifp->if_output)(ifp, frag_hdr, first_hop, rt); +#endif /* TROLL */ + + /* + * Tough situation: if the error occured on the last + * fragment, we can not send an ER, as the if_output + * routine consumed the packet. If the error occured + * on any intermediate packets, we can send an ER + * because we still have the original header in (m). + */ + if (error) { + if (frag_hdr != hdr) { + /* + * The error was not on the last fragment. We must + * free hdr and m before returning + */ + clnp_discard(hdr, GEN_NOREAS); + m_freem(m); + } + return(error); + } + + /* bump segment offset, trim data mbuf, and decrement count left */ +#ifdef TROLL + /* + * Decrement frag_size by some fraction. This will cause the + * next fragment to start 'early', thus duplicating the end + * of the current fragment. troll.tr_dup_size controls + * the fraction. If positive, it specifies the fraction. If + * negative, a random fraction is used. + */ + if ((trollctl.tr_ops & TR_DUPEND) && (!last_frag)) { + int num_bytes = frag_size; + + if (trollctl.tr_dup_size > 0) + num_bytes *= trollctl.tr_dup_size; + else + num_bytes *= troll_random(); + frag_size -= num_bytes; + } +#endif /* TROLL */ + total_len -= frag_size; + if (!last_frag) { + frag_base += frag_size; + seg_part.cng_off = htons(frag_base); + m_adj(m, frag_size); + } + } + return(0); + } else { + cantfrag: + INCSTAT(cns_cantfrag); + clnp_discard(m, GEN_SEGNEEDED); + return(EMSGSIZE); + } +} + +/* + * FUNCTION: clnp_reass + * + * PURPOSE: Attempt to reassemble a clnp packet given the current + * fragment. If reassembly succeeds (all the fragments + * are present), then return a pointer to an mbuf chain + * containing the reassembled packet. This packet will + * appear in the mbufs as if it had just arrived in + * one piece. + * + * If reassembly fails, then save this fragment and + * return 0. + * + * RETURNS: Ptr to assembled packet, or 0 + * + * SIDE EFFECTS: + * + * NOTES: + * clnp_slowtimo can not affect this code because clnpintr, and thus + * this code, is called at a higher priority than clnp_slowtimo. + */ +struct mbuf * +clnp_reass(m, src, dst, seg) +struct mbuf *m; /* new fragment */ +struct iso_addr *src; /* src of new fragment */ +struct iso_addr *dst; /* dst of new fragment */ +struct clnp_segment *seg; /* segment part of fragment header */ +{ + register struct clnp_fragl *cfh; + + /* look for other fragments of this datagram */ + for (cfh = clnp_frags; cfh != NULL; cfh = cfh->cfl_next) { + if (seg->cng_id == cfh->cfl_id && + iso_addrmatch1(src, &cfh->cfl_src) && + iso_addrmatch1(dst, &cfh->cfl_dst)) { + IFDEBUG(D_REASS) + printf("clnp_reass: found packet\n"); + ENDDEBUG + /* + * There are other fragments here already. Lets see if + * this fragment is of any help + */ + clnp_insert_frag(cfh, m, seg); + if (m = clnp_comp_pdu(cfh)) { + register struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); + HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, + seg->cng_tot_len); + } + return (m); + } + } + + IFDEBUG(D_REASS) + printf("clnp_reass: new packet!\n"); + ENDDEBUG + + /* + * This is the first fragment. If src is not consuming too many + * resources, then create a new fragment list and add + * this fragment to the list. + */ + /* TODO: don't let one src hog all the reassembly buffers */ + if (!clnp_newpkt(m, src, dst, seg) /* || this src is a hog */) { + INCSTAT(cns_fragdropped); + clnp_discard(m, GEN_CONGEST); + } + + return(NULL); +} + +/* + * FUNCTION: clnp_newpkt + * + * PURPOSE: Create the necessary structures to handle a new + * fragmented clnp packet. + * + * RETURNS: non-zero if it succeeds, zero if fails. + * + * SIDE EFFECTS: + * + * NOTES: Failure is only due to insufficient resources. + */ +clnp_newpkt(m, src, dst, seg) +struct mbuf *m; /* new fragment */ +struct iso_addr *src; /* src of new fragment */ +struct iso_addr *dst; /* dst of new fragment */ +struct clnp_segment *seg; /* segment part of fragment header */ +{ + register struct clnp_fragl *cfh; + register struct clnp_fixed *clnp; + struct mbuf *m0; + + clnp = mtod(m, struct clnp_fixed *); + + /* + * Allocate new clnp fragl structure to act as header of all fragments + * for this datagram. + */ + MGET(m0, M_DONTWAIT, MT_FTABLE); + if (m0 == NULL) { + return (0); + } + cfh = mtod(m0, struct clnp_fragl *); + + /* + * Duplicate the header of this fragment, and save in cfh. + * Free m0 and return if m_copy does not succeed. + */ + if ((cfh->cfl_orighdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) == NULL) { + m_freem(m0); + return (0); + } + + /* Fill in rest of fragl structure */ + bcopy((caddr_t)src, (caddr_t)&cfh->cfl_src, sizeof(struct iso_addr)); + bcopy((caddr_t)dst, (caddr_t)&cfh->cfl_dst, sizeof(struct iso_addr)); + cfh->cfl_id = seg->cng_id; + cfh->cfl_ttl = clnp->cnf_ttl; + cfh->cfl_last = (seg->cng_tot_len - clnp->cnf_hdr_len) - 1; + cfh->cfl_frags = NULL; + cfh->cfl_next = NULL; + + /* Insert into list of packets */ + cfh->cfl_next = clnp_frags; + clnp_frags = cfh; + + /* Insert this fragment into list headed by cfh */ + clnp_insert_frag(cfh, m, seg); + return(1); +} + +/* + * FUNCTION: clnp_insert_frag + * + * PURPOSE: Insert fragment into list headed by 'cf'. + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: This is the 'guts' of the reassembly algorithm. + * Each fragment in this list contains a clnp_frag + * structure followed by the data of the fragment. + * The clnp_frag structure actually lies on top of + * part of the old clnp header. + */ +clnp_insert_frag(cfh, m, seg) +struct clnp_fragl *cfh; /* header of list of packet fragments */ +struct mbuf *m; /* new fragment */ +struct clnp_segment *seg; /* segment part of fragment header */ +{ + register struct clnp_fixed *clnp; /* clnp hdr of fragment */ + register struct clnp_frag *cf; /* generic fragment ptr */ + register struct clnp_frag *cf_sub = NULL; /* frag subsequent to new one */ + register struct clnp_frag *cf_prev = NULL; /* frag previous to new one */ + u_short first; /* offset of first byte of initial pdu*/ + u_short last; /* offset of last byte of initial pdu */ + u_short fraglen;/* length of fragment */ + + clnp = mtod(m, struct clnp_fixed *); + first = seg->cng_off; + CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, fraglen); + fraglen -= clnp->cnf_hdr_len; + last = (first + fraglen) - 1; + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: New fragment: [%d ... %d], len %d\n", + first, last, fraglen); + printf("clnp_insert_frag: current fragments:\n"); + for (cf = cfh->cfl_frags; cf != NULL; cf = cf->cfr_next) { + printf("\tcf x%x: [%d ... %d]\n", cf, cf->cfr_first, cf->cfr_last); + } + ENDDEBUG + + if (cfh->cfl_frags != NULL) { + /* + * Find fragment which begins after the new one + */ + for (cf = cfh->cfl_frags; cf != NULL; cf_prev = cf, cf = cf->cfr_next) { + if (cf->cfr_first > first) { + cf_sub = cf; + break; + } + } + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: Previous frag is "); + if (cf_prev == NULL) + printf("NULL\n"); + else + printf("[%d ... %d]\n", cf_prev->cfr_first, cf_prev->cfr_last); + printf("clnp_insert_frag: Subsequent frag is "); + if (cf_sub == NULL) + printf("NULL\n"); + else + printf("[%d ... %d]\n", cf_sub->cfr_first, cf_sub->cfr_last); + ENDDEBUG + + /* + * If there is a fragment before the new one, check if it + * overlaps the new one. If so, then trim the end of the + * previous one. + */ + if (cf_prev != NULL) { + if (cf_prev->cfr_last > first) { + u_short overlap = cf_prev->cfr_last - first; + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: previous overlaps by %d\n", + overlap); + ENDDEBUG + + if (overlap > fraglen) { + /* + * The new fragment is entirely contained in the + * preceeding one. We can punt on the new frag + * completely. + */ + m_freem(m); + return; + } else { + /* Trim data off of end of previous fragment */ + /* inc overlap to prevent duplication of last byte */ + overlap++; + m_adj(cf_prev->cfr_data, -(int)overlap); + cf_prev->cfr_last -= overlap; + } + } + } + + /* + * For all fragments past the new one, check if any data on + * the new one overlaps data on existing fragments. If so, + * then trim the extra data off the end of the new one. + */ + for (cf = cf_sub; cf != NULL; cf = cf->cfr_next) { + if (cf->cfr_first < last) { + u_short overlap = last - cf->cfr_first; + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: subsequent overlaps by %d\n", + overlap); + ENDDEBUG + + if (overlap > fraglen) { + /* + * The new fragment is entirely contained in the + * succeeding one. This should not happen, because + * early on in this code we scanned for the fragment + * which started after the new one! + */ + m_freem(m); + printf("clnp_insert_frag: internal error!\n"); + return; + } else { + /* Trim data off of end of new fragment */ + /* inc overlap to prevent duplication of last byte */ + overlap++; + m_adj(m, -(int)overlap); + last -= overlap; + } + } + } + } + + /* + * Insert the new fragment beween cf_prev and cf_sub + * + * Note: the clnp hdr is still in the mbuf. + * If the data of the mbuf is not word aligned, shave off enough + * so that it is. Then, cast the clnp_frag structure on top + * of the clnp header. + * The clnp_hdr will not be used again (as we already have + * saved a copy of it). + * + * Save in cfr_bytes the number of bytes to shave off to get to + * the data of the packet. This is used when we coalesce fragments; + * the clnp_frag structure must be removed before joining mbufs. + */ + { + int pad; + u_int bytes; + + /* determine if header is not word aligned */ + pad = (int)clnp % 4; + if (pad < 0) + pad = -pad; + + /* bytes is number of bytes left in front of data */ + bytes = clnp->cnf_hdr_len - pad; + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: clnp x%x requires %d alignment\n", + clnp, pad); + ENDDEBUG + + /* make it word aligned if necessary */ + if (pad) + m_adj(m, pad); + + cf = mtod(m, struct clnp_frag *); + cf->cfr_bytes = bytes; + + IFDEBUG(D_REASS) + printf("clnp_insert_frag: cf now x%x, cfr_bytes %d\n", cf, + cf->cfr_bytes); + ENDDEBUG + } + cf->cfr_first = first; + cf->cfr_last = last; + + + /* + * The data is the mbuf itself, although we must remember that the + * first few bytes are actually a clnp_frag structure + */ + cf->cfr_data = m; + + /* link into place */ + cf->cfr_next = cf_sub; + if (cf_prev == NULL) + cfh->cfl_frags = cf; + else + cf_prev->cfr_next = cf; +} + +/* + * FUNCTION: clnp_comp_pdu + * + * PURPOSE: Scan the list of fragments headed by cfh. Merge + * any contigious fragments into one. If, after + * traversing all the fragments, it is determined that + * the packet is complete, then return a pointer to + * the packet (with header prepended). Otherwise, + * return NULL. + * + * RETURNS: NULL, or a pointer to the assembled pdu in an mbuf chain. + * + * SIDE EFFECTS: Will colapse contigious fragments into one. + * + * NOTES: This code assumes that there are no overlaps of + * fragment pdus. + */ +struct mbuf * +clnp_comp_pdu(cfh) +struct clnp_fragl *cfh; /* fragment header */ +{ + register struct clnp_frag *cf = cfh->cfl_frags; + + while (cf->cfr_next != NULL) { + register struct clnp_frag *cf_next = cf->cfr_next; + + IFDEBUG(D_REASS) + printf("clnp_comp_pdu: comparing: [%d ... %d] to [%d ... %d]\n", + cf->cfr_first, cf->cfr_last, cf_next->cfr_first, + cf_next->cfr_last); + ENDDEBUG + + if (cf->cfr_last == (cf_next->cfr_first - 1)) { + /* + * Merge fragment cf and cf_next + * + * - update cf header + * - trim clnp_frag structure off of cf_next + * - append cf_next to cf + */ + struct clnp_frag cf_next_hdr; + struct clnp_frag *next_frag; + + cf_next_hdr = *cf_next; + next_frag = cf_next->cfr_next; + + IFDEBUG(D_REASS) + struct mbuf *mdump; + int l; + printf("clnp_comp_pdu: merging fragments\n"); + printf("clnp_comp_pdu: 1st: [%d ... %d] (bytes %d)\n", + cf->cfr_first, cf->cfr_last, cf->cfr_bytes); + mdump = cf->cfr_data; + l = 0; + while (mdump != NULL) { + printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); + l += mdump->m_len; + mdump = mdump->m_next; + } + printf("\ttotal len: %d\n", l); + printf("clnp_comp_pdu: 2nd: [%d ... %d] (bytes %d)\n", + cf_next->cfr_first, cf_next->cfr_last, cf_next->cfr_bytes); + mdump = cf_next->cfr_data; + l = 0; + while (mdump != NULL) { + printf("\tmbuf x%x, m_len %d\n", mdump, mdump->m_len); + l += mdump->m_len; + mdump = mdump->m_next; + } + printf("\ttotal len: %d\n", l); + ENDDEBUG + + cf->cfr_last = cf_next->cfr_last; + /* + * After this m_adj, the cf_next ptr is useless because we + * have adjusted the clnp_frag structure away... + */ + IFDEBUG(D_REASS) + printf("clnp_comp_pdu: shaving off %d bytes\n", + cf_next_hdr.cfr_bytes); + ENDDEBUG + m_adj(cf_next_hdr.cfr_data, (int)cf_next_hdr.cfr_bytes); + m_cat(cf->cfr_data, cf_next_hdr.cfr_data); + cf->cfr_next = next_frag; + } else { + cf = cf->cfr_next; + } + } + + cf = cfh->cfl_frags; + + IFDEBUG(D_REASS) + struct mbuf *mdump = cf->cfr_data; + printf("clnp_comp_pdu: first frag now: [%d ... %d]\n", cf->cfr_first, + cf->cfr_last); + printf("clnp_comp_pdu: data for frag:\n"); + while (mdump != NULL) { + printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); +/* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ + mdump = mdump->m_next; + } + ENDDEBUG + + /* Check if datagram is complete */ + if ((cf->cfr_first == 0) && (cf->cfr_last == cfh->cfl_last)) { + /* + * We have a complete pdu! + * - Remove the frag header from (only) remaining fragment + * (which is not really a fragment anymore, as the datagram is + * complete). + * - Prepend a clnp header + */ + struct mbuf *data = cf->cfr_data; + struct mbuf *hdr = cfh->cfl_orighdr; + struct clnp_fragl *scan; + + IFDEBUG(D_REASS) + printf("clnp_comp_pdu: complete pdu!\n"); + ENDDEBUG + + m_adj(data, (int)cf->cfr_bytes); + m_cat(hdr, data); + + IFDEBUG(D_DUMPIN) + struct mbuf *mdump = hdr; + printf("clnp_comp_pdu: pdu is:\n"); + while (mdump != NULL) { + printf("mbuf x%x, m_len %d\n", mdump, mdump->m_len); +/* dump_buf(mtod(mdump, caddr_t), mdump->m_len);*/ + mdump = mdump->m_next; + } + ENDDEBUG + + /* + * Remove cfh from the list of fragmented pdus + */ + if (clnp_frags == cfh) { + clnp_frags = cfh->cfl_next; + } else { + for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { + if (scan->cfl_next == cfh) { + scan->cfl_next = cfh->cfl_next; + break; + } + } + } + + /* free cfh */ + m_freem(dtom(cfh)); + + return(hdr); + } + + return(NULL); +} +#ifdef TROLL +static int troll_cnt; +#include <sys/time.h> +/* + * FUNCTION: troll_random + * + * PURPOSE: generate a pseudo-random number between 0 and 1 + * + * RETURNS: the random number + * + * SIDE EFFECTS: + * + * NOTES: This is based on the clock. + */ +float troll_random() +{ + extern struct timeval time; + long t = time.tv_usec % 100; + + return((float)t / (float) 100); +} + +/* + * FUNCTION: troll_output + * + * PURPOSE: Do something sneaky with the datagram passed. Possible + * operations are: + * Duplicate the packet + * Drop the packet + * Trim some number of bytes from the packet + * Munge some byte in the packet + * + * RETURNS: 0, or unix error code + * + * SIDE EFFECTS: + * + * NOTES: The operation of this procedure is regulated by the + * troll control structure (Troll). + */ +troll_output(ifp, m, dst, rt) +struct ifnet *ifp; +struct mbuf *m; +struct sockaddr *dst; +struct rtentry *rt; +{ + int err = 0; + troll_cnt++; + + if (trollctl.tr_ops & TR_DUPPKT) { + /* + * Duplicate every Nth packet + * TODO: random? + */ + float f_freq = troll_cnt * trollctl.tr_dup_freq; + int i_freq = troll_cnt * trollctl.tr_dup_freq; + if (i_freq == f_freq) { + struct mbuf *dup = m_copy(m, 0, (int)M_COPYALL); + if (dup != NULL) + err = (*ifp->if_output)(ifp, dup, dst, rt); + } + if (!err) + err = (*ifp->if_output)(ifp, m, dst, rt); + return(err); + } else if (trollctl.tr_ops & TR_DROPPKT) { + } else if (trollctl.tr_ops & TR_CHANGE) { + struct clnp_fixed *clnp = mtod(m, struct clnp_fixed *); + clnp->cnf_cksum_msb = 0; + err = (*ifp->if_output)(ifp, m, dst, rt); + return(err); + } else { + err = (*ifp->if_output)(ifp, m, dst, rt); + return(err); + } +} + +#endif /* TROLL */ diff --git a/sys/netiso/clnp_input.c b/sys/netiso/clnp_input.c new file mode 100644 index 0000000..c49de95 --- /dev/null +++ b/sys/netiso/clnp_input.c @@ -0,0 +1,551 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_input.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_input.c,v 5.1 89/02/09 16:20:32 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_input.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#include <netiso/clnp.h> +#include <netiso/clnl.h> +#include <netiso/esis.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/if_ether.h> +#include <netiso/eonvar.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +#ifdef ISO +u_char clnp_protox[ISOPROTO_MAX]; +struct clnl_protosw clnl_protox[256]; +int clnpqmaxlen = IFQ_MAXLEN; /* RAH? why is this a variable */ +struct mbuf *clnp_data_ck(); + +int clnp_input(); + +int esis_input(); + +#ifdef ISO_X25ESIS +int x25esis_input(); +#endif /* ISO_X25ESIS */ + +/* + * FUNCTION: clnp_init + * + * PURPOSE: clnp initialization. Fill in clnp switch tables. + * + * RETURNS: none + * + * SIDE EFFECTS: fills in clnp_protox table with correct offsets into + * the isosw table. + * + * NOTES: + */ +clnp_init() +{ + register struct protosw *pr; + + /* + * CLNP protox initialization + */ + if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0) + printf("clnl_init: no raw CLNP\n"); + else + clnp_protox[ISOPROTO_RAW] = pr - isosw; + + if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0) + printf("clnl_init: no tp/clnp\n"); + else + clnp_protox[ISOPROTO_TP] = pr - isosw; + + /* + * CLNL protox initialization + */ + clnl_protox[ISO8473_CLNP].clnl_input = clnp_input; + + clnlintrq.ifq_maxlen = clnpqmaxlen; +} + +/* + * FUNCTION: clnlintr + * + * PURPOSE: Process a packet on the clnl input queue + * + * RETURNS: nothing. + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnlintr() +{ + register struct mbuf *m; /* ptr to first mbuf of pkt */ + register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */ + int s; /* save and restore priority */ + struct clnl_protosw *clnlsw;/* ptr to protocol switch */ + struct snpa_hdr sh; /* subnetwork hdr */ + + /* + * Get next datagram off clnl input queue + */ +next: + s = splimp(); + /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/ + IF_DEQUEUE(&clnlintrq, m); + splx(s); + + + if (m == 0) /* nothing to do */ + return; + if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) { + m_freem(m); + goto next; + } else { + register struct ifaddr *ifa; + for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_ISO) + break; + if (ifa == 0) { + m_freem(m); + goto next; + } + } + bzero((caddr_t)&sh, sizeof(sh)); + sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST); + switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) { + extern int ether_output(); + case IFT_EON: + bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long)); + bcopy(sizeof(u_long) + mtod(m, caddr_t), + (caddr_t)sh.snh_shost, sizeof(u_long)); + sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) + + _offsetof(struct eon_hdr, eonh_class)]; + m->m_data += EONIPLEN; + m->m_len -= EONIPLEN; + m->m_pkthdr.len -= EONIPLEN; + break; + + default: + if (sh.snh_ifp->if_output == ether_output) { + bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost), + (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost)); + m->m_data += sizeof (struct ether_header); + m->m_len -= sizeof (struct ether_header); + m->m_pkthdr.len -= sizeof (struct ether_header); + } + } + IFDEBUG(D_INPUT) + int i; + printf("clnlintr: src:"); + for (i=0; i<6; i++) + printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' '); + printf(" dst:"); + for (i=0; i<6; i++) + printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' '); + printf("\n"); + ENDDEBUG + + /* + * Get the fixed part of the clnl header into the first mbuf. + * Drop the packet if this fails. + * Do not call m_pullup if we have a cluster mbuf or the + * data is not there. + */ + if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) && + ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) { + INCSTAT(cns_toosmall); /* TODO: use clnl stats */ + goto next; /* m_pullup discards mbuf */ + } + + clnl = mtod(m, struct clnl_fixed *); + + /* + * Drop packet if the length of the header is not reasonable. + */ + if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) || + (clnl->cnf_hdr_len > CLNP_HDR_MAX)) { + INCSTAT(cns_badhlen); /* TODO: use clnl stats */ + m_freem(m); + goto next; + } + + /* + * If the header is not contained in this mbuf, make it so. + * Drop packet if this fails. + * Note: m_pullup will allocate a cluster mbuf if necessary + */ + if (clnl->cnf_hdr_len > m->m_len) { + if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) { + INCSTAT(cns_badhlen); /* TODO: use clnl stats */ + goto next; /* m_pullup discards mbuf */ + } + clnl = mtod(m, struct clnl_fixed *); + } + + clnlsw = &clnl_protox[clnl->cnf_proto_id]; + + + if (clnlsw->clnl_input) + (*clnlsw->clnl_input) (m, &sh); + else + m_freem(m); + + goto next; +} + +/* + * FUNCTION: clnp_input + * + * PURPOSE: process an incoming clnp packet + * + * RETURNS: nothing + * + * SIDE EFFECTS: increments fields of clnp_stat structure. + * + * NOTES: + * TODO: I would like to make seg_part a pointer into the mbuf, but + * will it be correctly aligned? + */ +clnp_input(m, shp) +struct mbuf *m; /* ptr to first mbuf of pkt */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + register struct clnp_fixed *clnp; /* ptr to fixed part of header */ + struct sockaddr_iso source; /* source address of pkt */ + struct sockaddr_iso target; /* destination address of pkt */ +#define src source.siso_addr +#define dst target.siso_addr + caddr_t hoff; /* current offset in packet */ + caddr_t hend; /* address of end of header info */ + struct clnp_segment seg_part; /* segment part of hdr */ + int seg_off=0; /* offset of segment part of hdr */ + int seg_len;/* length of packet data&hdr in bytes */ + struct clnp_optidx oidx, *oidxp = NULL; /* option index */ + extern int iso_systype; /* used by ESIS config resp */ + extern struct sockaddr_iso blank_siso; /* used for initializing */ + int need_afrin = 0; + /* true if congestion experienced */ + /* which means you need afrin nose */ + /* spray. How clever! */ + + IFDEBUG(D_INPUT) + printf( + "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n", + m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal"); + ENDDEBUG + need_afrin = 0; + + /* + * If no iso addresses have been set, there is nothing + * to do with the packet. + */ + if (iso_ifaddr == NULL) { + clnp_discard(m, ADDR_DESTUNREACH); + return; + } + + INCSTAT(cns_total); + clnp = mtod(m, struct clnp_fixed *); + + IFDEBUG(D_DUMPIN) + struct mbuf *mhead; + int total_len = 0; + printf("clnp_input: clnp header:\n"); + dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len); + printf("clnp_input: mbuf chain:\n"); + for (mhead = m; mhead != NULL; mhead=mhead->m_next) { + printf("m x%x, len %d\n", mhead, mhead->m_len); + total_len += mhead->m_len; + } + printf("clnp_input: total length of mbuf chain %d:\n", total_len); + ENDDEBUG + + /* + * Compute checksum (if necessary) and drop packet if + * checksum does not match + */ + if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) { + INCSTAT(cns_badcsum); + clnp_discard(m, GEN_BADCSUM); + return; + } + + if (clnp->cnf_vers != ISO8473_V1) { + INCSTAT(cns_badvers); + clnp_discard(m, DISC_UNSUPPVERS); + return; + } + + + /* check mbuf data length: clnp_data_ck will free mbuf upon error */ + CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len); + if ((m = clnp_data_ck(m, seg_len)) == 0) + return; + + clnp = mtod(m, struct clnp_fixed *); + hend = (caddr_t)clnp + clnp->cnf_hdr_len; + + /* + * extract the source and destination address + * drop packet on failure + */ + source = target = blank_siso; + + hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); + CLNP_EXTRACT_ADDR(dst, hoff, hend); + if (hoff == (caddr_t)0) { + INCSTAT(cns_badaddr); + clnp_discard(m, GEN_INCOMPLETE); + return; + } + CLNP_EXTRACT_ADDR(src, hoff, hend); + if (hoff == (caddr_t)0) { + INCSTAT(cns_badaddr); + clnp_discard(m, GEN_INCOMPLETE); + return; + } + + IFDEBUG(D_INPUT) + printf("clnp_input: from %s", clnp_iso_addrp(&src)); + printf(" to %s\n", clnp_iso_addrp(&dst)); + ENDDEBUG + + /* + * extract the segmentation information, if it is present. + * drop packet on failure + */ + if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && + (clnp->cnf_type & CNF_SEG_OK)) { + if (hoff + sizeof(struct clnp_segment) > hend) { + INCSTAT(cns_noseg); + clnp_discard(m, GEN_INCOMPLETE); + return; + } else { + (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment)); + /* make sure segmentation fields are in host order */ + seg_part.cng_id = ntohs(seg_part.cng_id); + seg_part.cng_off = ntohs(seg_part.cng_off); + seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len); + seg_off = hoff - (caddr_t)clnp; + hoff += sizeof(struct clnp_segment); + } + } + + /* + * process options if present. If clnp_opt_sanity returns + * false (indicating an error was found in the options) or + * an unsupported option was found + * then drop packet and emit an ER. + */ + if (hoff < hend) { + int errcode; + + oidxp = &oidx; + errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp); + + /* we do not support security */ + if ((errcode == 0) && (oidxp->cni_securep)) + errcode = DISC_UNSUPPSECURE; + + /* the er option is valid with ER pdus only */ + if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) && + ((clnp->cnf_type & CNF_TYPE) != CLNP_ER)) + errcode = DISC_UNSUPPOPT; + +#ifdef DECBIT + /* check if the congestion experienced bit is set */ + if (oidxp->cni_qos_formatp) { + caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp); + u_char qos = *qosp; + + need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) == + (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)); + if (need_afrin) + INCSTAT(cns_congest_rcvd); + } +#endif /* DECBIT */ + + if (errcode != 0) { + clnp_discard(m, (char)errcode); + IFDEBUG(D_INPUT) + printf("clnp_input: dropped (err x%x) due to bad options\n", + errcode); + ENDDEBUG + return; + } + } + + /* + * check if this packet is for us. if not, then forward + */ + if (clnp_ours(&dst) == 0) { + IFDEBUG(D_INPUT) + printf("clnp_input: forwarding packet not for us\n"); + ENDDEBUG + clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp); + return; + } + + /* + * ESIS Configuration Response Function + * + * If the packet received was sent to the multicast address + * all end systems, then send an esh to the source + */ + if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) { + extern short esis_holding_time; + + esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time, + shp->snh_shost, 6, &dst); + } + + /* + * If this is a fragment, then try to reassemble it. If clnp_reass + * returns non NULL, the packet has been reassembled, and should + * be give to TP. Otherwise the fragment has been delt with + * by the reassembly code (either stored or deleted). In either case + * we should have nothing more to do with it. + */ + if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) && + (clnp->cnf_type & CNF_SEG_OK) && + (seg_len != seg_part.cng_tot_len)) { + struct mbuf *m0; + + if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) { + m = m0; + clnp = mtod(m, struct clnp_fixed *); + INCSTAT(cns_reassembled); + } else { + return; + } + } + + /* + * give the packet to the higher layer + * + * Note: the total length of packet + * is the total length field of the segmentation part, + * or, if absent, the segment length field of the + * header. + */ + INCSTAT(cns_delivered); + switch (clnp->cnf_type & CNF_TYPE) { + case CLNP_ER: + /* + * This ER must have the er option. + * If the option is not present, discard datagram. + */ + if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) { + clnp_discard(m, GEN_HDRSYNTAX); + } else { + clnp_er_input(m, &src, oidxp->cni_er_reason); + } + break; + + case CLNP_DT: + (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target, + clnp->cnf_hdr_len, need_afrin); + break; + + case CLNP_RAW: + case CLNP_ECR: + IFDEBUG(D_INPUT) + printf("clnp_input: raw input of %d bytes\n", + clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len); + ENDDEBUG + (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target, + clnp->cnf_hdr_len); + break; + + case CLNP_EC: + IFDEBUG(D_INPUT) + printf("clnp_input: echoing packet\n"); + ENDDEBUG + (void)clnp_echoreply(m, + (clnp->cnf_type & CNF_SEG_OK ? (int)seg_part.cng_tot_len : seg_len), + &source, &target, oidxp); + break; + + default: + printf("clnp_input: unknown clnp pkt type %d\n", + clnp->cnf_type & CNF_TYPE); + clnp_stat.cns_delivered--; + clnp_stat.cns_noproto++; + clnp_discard(m, GEN_HDRSYNTAX); + break; + } +} +#endif /* ISO */ diff --git a/sys/netiso/clnp_options.c b/sys/netiso/clnp_options.c new file mode 100644 index 0000000..250b438 --- /dev/null +++ b/sys/netiso/clnp_options.c @@ -0,0 +1,532 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_options.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_options.c,v 5.1 89/02/09 16:20:37 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_options.c,v $ */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +/* + * FUNCTION: clnp_update_srcrt + * + * PURPOSE: Process src rt option accompanying a clnp datagram. + * - bump src route ptr if src routing and + * we appear current in src route list. + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: If source routing has been terminated, do nothing. + */ +clnp_update_srcrt(options, oidx) +struct mbuf *options; /* ptr to options mbuf */ +struct clnp_optidx *oidx; /* ptr to option index */ +{ + u_char len; /* length of current address */ + struct iso_addr isoa; /* copy current address into here */ + + if (CLNPSRCRT_TERM(oidx, options)) { + IFDEBUG(D_OPTIONS) + printf("clnp_update_srcrt: src rt terminated\n"); + ENDDEBUG + return; + } + + len = CLNPSRCRT_CLEN(oidx, options); + bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&isoa, len); + isoa.isoa_len = len; + + IFDEBUG(D_OPTIONS) + printf("clnp_update_srcrt: current src rt: %s\n", + clnp_iso_addrp(&isoa)); + ENDDEBUG + + if (clnp_ours(&isoa)) { + IFDEBUG(D_OPTIONS) + printf("clnp_update_srcrt: updating src rt\n"); + ENDDEBUG + + /* update pointer to next src route */ + len++; /* count length byte too! */ + CLNPSRCRT_OFF(oidx, options) += len; + } +} + +/* + * FUNCTION: clnp_dooptions + * + * PURPOSE: Process options accompanying a clnp datagram. + * Processing includes + * - log our address if recording route + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_dooptions(options, oidx, ifp, isoa) +struct mbuf *options; /* ptr to options mbuf */ +struct clnp_optidx *oidx; /* ptr to option index */ +struct ifnet *ifp; /* ptr to interface pkt is leaving on */ +struct iso_addr *isoa; /* ptr to our address for this ifp */ +{ + /* + * If record route is specified, move all + * existing records over, and insert the address of + * interface passed + */ + if (oidx->cni_recrtp) { + char *opt; /* ptr to beginning of recrt option */ + u_char off; /* offset from opt of first free byte */ + char *rec_start; /* beginning of new rt recorded */ + + opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp); + off = *(opt + 1); + rec_start = opt + off - 1; + + IFDEBUG(D_OPTIONS) + printf("clnp_dooptions: record route: option x%x for %d bytes\n", + opt, oidx->cni_recrt_len); + printf("\tfree slot offset x%x\n", off); + printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa)); + printf("clnp_dooptions: option dump:\n"); + dump_buf(opt, oidx->cni_recrt_len); + ENDDEBUG + + /* proceed only if recording has not been terminated */ + if (off != 0xff) { + int new_addrlen = isoa->isoa_len + 1; + /* + * if there is insufficient room to store the next address, + * then terminate recording. Plus 1 on isoa_len is for the + * length byte itself + */ + if (oidx->cni_recrt_len - (off - 1) < new_addrlen) { + *(opt + 1) = 0xff; /* terminate recording */ + } else { + IFDEBUG(D_OPTIONS) + printf("clnp_dooptions: new addr at x%x for %d\n", + rec_start, new_addrlen); + ENDDEBUG + + bcopy((caddr_t)isoa, rec_start, new_addrlen); + + /* update offset field */ + *(opt + 1) += new_addrlen; + + IFDEBUG(D_OPTIONS) + printf("clnp_dooptions: new option dump:\n"); + dump_buf(opt, oidx->cni_recrt_len); + ENDDEBUG + } + } + } +} + +/* + * FUNCTION: clnp_set_opts + * + * PURPOSE: Check the data mbuf passed for option sanity. If it is + * ok, then set the options ptr to address the data mbuf. + * If an options mbuf exists, free it. This implies that + * any old options will be lost. If data is NULL, simply + * free any old options. + * + * RETURNS: unix error code + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_set_opts(options, data) +struct mbuf **options; /* target for option information */ +struct mbuf **data; /* source of option information */ +{ + int error = 0; /* error return value */ + struct clnp_optidx dummy; /* dummy index - not used */ + + /* + * remove any existing options + */ + if (*options != NULL) { + m_freem(*options); + *options = NULL; + } + + if (*data != NULL) { + /* + * Insure that the options are reasonable. + * + * Also, we do not support security, priority, + * nor do we allow one to send an ER option + * + * The QOS parameter is checked for the DECBIT. + */ + if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len, + &dummy) != 0) || + (dummy.cni_securep) || + (dummy.cni_priorp) || + (dummy.cni_er_reason != ER_INVALREAS)) { + error = EINVAL; + } else { + *options = *data; + *data = NULL; /* so caller won't free mbuf @ *data */ + } + } + return error; +} + +/* + * FUNCTION: clnp_opt_sanity + * + * PURPOSE: Check the options (beginning at opts for len bytes) for + * sanity. In addition, fill in the option index structure + * in with information about each option discovered. + * + * RETURNS: success (options check out) - 0 + * failure - an ER pdu error code describing failure + * + * SIDE EFFECTS: + * + * NOTES: Each pointer field of the option index is filled in with + * the offset from the beginning of the mbuf data, not the + * actual address. + */ +clnp_opt_sanity(m, opts, len, oidx) +struct mbuf *m; /* mbuf options reside in */ +caddr_t opts; /* ptr to buffer containing options */ +int len; /* length of buffer */ +struct clnp_optidx *oidx; /* RETURN: filled in with option idx info */ +{ + u_char opcode; /* code of particular option */ + u_char oplen; /* length of a particular option */ + caddr_t opts_end; /* ptr to end of options */ + u_char pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0; + /* flags for catching duplicate options */ + + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: checking %d bytes of data:\n", len); + dump_buf(opts, len); + ENDDEBUG + + /* clear option index field if passed */ + bzero((caddr_t)oidx, sizeof(struct clnp_optidx)); + + /* + * We need to indicate whether the ER option is present. This is done + * by overloading the er_reason field to also indicate presense of + * the option along with the option value. I would like ER_INVALREAS + * to have value 0, but alas, 0 is a valid er reason... + */ + oidx->cni_er_reason = ER_INVALREAS; + + opts_end = opts + len; + while (opts < opts_end) { + /* must have at least 2 bytes per option (opcode and len) */ + if (opts + 2 > opts_end) + return(GEN_INCOMPLETE); + + opcode = *opts++; + oplen = *opts++; + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: opcode is %x and oplen %d\n", + opcode, oplen); + printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT); + + switch (opcode) { + case CLNPOVAL_PAD: { + printf("CLNPOVAL_PAD\n"); + } break; + case CLNPOVAL_SECURE: { + printf("CLNPOVAL_SECURE\n"); + } break; + case CLNPOVAL_SRCRT: { + printf("CLNPOVAL_SRCRT\n"); + } break; + case CLNPOVAL_RECRT: { + printf("CLNPOVAL_RECRT\n"); + } break; + case CLNPOVAL_QOS: { + printf("CLNPOVAL_QOS\n"); + } break; + case CLNPOVAL_PRIOR: { + printf("CLNPOVAL_PRIOR\n"); + } break; + case CLNPOVAL_ERREAS: { + printf("CLNPOVAL_ERREAS\n"); + } break; + default: + printf("UKNOWN option %x\n", opcode); + } + ENDDEBUG + + /* don't allow crazy length values */ + if (opts + oplen > opts_end) + return(GEN_INCOMPLETE); + + switch (opcode) { + case CLNPOVAL_PAD: + /* + * Padding: increment pointer by length of padding + */ + if (pad++) /* duplicate ? */ + return(GEN_DUPOPT); + opts += oplen; + break; + + case CLNPOVAL_SECURE: { + u_char format = *opts; + + if (secure++) /* duplicate ? */ + return(GEN_DUPOPT); + /* + * Security: high 2 bits of first octet indicate format + * (00 in high bits is reserved). + * Remaining bits must be 0. Remaining octets indicate + * actual security + */ + if (((format & 0x3f) > 0) || /* low 6 bits set ? */ + ((format & 0xc0) == 0)) /* high 2 bits zero ? */ + return(GEN_HDRSYNTAX); + + oidx->cni_securep = CLNP_OPTTOOFF(m, opts); + oidx->cni_secure_len = oplen; + opts += oplen; + } break; + + case CLNPOVAL_SRCRT: { + u_char type, offset; /* type of rt, offset of start */ + caddr_t route_end; /* address of end of route option */ + + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: SRC RT\n"); + ENDDEBUG + + if (srcrt++) /* duplicate ? */ + return(GEN_DUPOPT); + /* + * source route: There must be 2 bytes following the length + * field: type and offset. The type must be either + * partial route or complete route. The offset field must + * be within the option. A single exception is made, however. + * The offset may be 1 greater than the length. This case + * occurs when the last source route record is consumed. + * In this case, we ignore the source route option. + * RAH? You should be able to set offset to 'ff' like in record + * route! + * Following this is a series of address fields. + * Each address field is composed of a (length, address) pair. + * Insure that the offset and each address length is reasonable + */ + route_end = opts + oplen; + + if (opts + 2 > route_end) + return(SRCRT_SYNTAX); + + type = *opts; + offset = *(opts+1); + + + /* type must be partial or complete */ + if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) + return(SRCRT_SYNTAX); + + oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts); + oidx->cni_srcrt_len = oplen; + + opts += offset-1; /*set opts to first addr in rt */ + + /* + * Offset must be reasonable: + * less than end of options, or equal to end of options + */ + if (opts >= route_end) { + if (opts == route_end) { + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: end of src route info\n"); + ENDDEBUG + break; + } else + return(SRCRT_SYNTAX); + } + + while (opts < route_end) { + u_char addrlen = *opts++; + if (opts + addrlen > route_end) + return(SRCRT_SYNTAX); + opts += addrlen; + } + } break; + case CLNPOVAL_RECRT: { + u_char type, offset; /* type of rt, offset of start */ + caddr_t record_end; /* address of end of record option */ + + if (recrt++) /* duplicate ? */ + return(GEN_DUPOPT); + /* + * record route: after the length field, expect a + * type and offset. Type must be partial or complete. + * Offset indicates where to start recording. Insure it + * is within the option. All ones for offset means + * recording is terminated. + */ + record_end = opts + oplen; + + oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts); + oidx->cni_recrt_len = oplen; + + if (opts + 2 > record_end) + return(GEN_INCOMPLETE); + + type = *opts; + offset = *(opts+1); + + /* type must be partial or complete */ + if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) + return(GEN_HDRSYNTAX); + + /* offset must be reasonable */ + if ((offset < 0xff) && (opts + offset > record_end)) + return(GEN_HDRSYNTAX); + opts += oplen; + } break; + case CLNPOVAL_QOS: { + u_char format = *opts; + + if (qos++) /* duplicate ? */ + return(GEN_DUPOPT); + /* + * qos: high 2 bits of first octet indicate format + * (00 in high bits is reserved). + * Remaining bits must be 0 (unless format indicates + * globally unique qos, in which case remaining bits indicate + * qos (except bit 6 which is reserved)). Otherwise, + * remaining octets indicate actual qos. + */ + if (((format & 0xc0) == 0) || /* high 2 bits zero ? */ + (((format & 0xc0) != CLNPOVAL_GLOBAL) && + ((format & 0x3f) > 0))) /* not global,low bits used ? */ + return(GEN_HDRSYNTAX); + + oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts); + oidx->cni_qos_len = oplen; + + opts += oplen; + } break; + + case CLNPOVAL_PRIOR: { + if (prior++) /* duplicate ? */ + return(GEN_DUPOPT); + /* + * priority: value must be one byte long + */ + if (oplen != 1) + return(GEN_HDRSYNTAX); + + oidx->cni_priorp = CLNP_OPTTOOFF(m, opts); + + opts += oplen; + } break; + + case CLNPOVAL_ERREAS: { + /* + * er reason: value must be two bytes long + */ + if (oplen != 2) + return(GEN_HDRSYNTAX); + + oidx->cni_er_reason = *opts; + + opts += oplen; + } break; + + default: { + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode); + ENDDEBUG + return(DISC_UNSUPPOPT); + } + } + } + IFDEBUG(D_OPTIONS) + printf("clnp_opt_sanity: return(0)\n", opcode); + ENDDEBUG + return(0); +} +#endif /* ISO */ diff --git a/sys/netiso/clnp_output.c b/sys/netiso/clnp_output.c new file mode 100644 index 0000000..aba9f6e --- /dev/null +++ b/sys/netiso/clnp_output.c @@ -0,0 +1,561 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_output.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_output.c,v 5.0 89/02/08 12:00:15 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_output.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_pcb.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +static struct clnp_fixed dt_template = { + ISO8473_CLNP, /* network identifier */ + 0, /* length */ + ISO8473_V1, /* version */ + CLNP_TTL, /* ttl */ + CLNP_DT|CNF_SEG_OK|CNF_ERR_OK, /* type */ + 0, /* segment length */ + 0 /* checksum */ +}; + +static struct clnp_fixed raw_template = { + ISO8473_CLNP, /* network identifier */ + 0, /* length */ + ISO8473_V1, /* version */ + CLNP_TTL, /* ttl */ + CLNP_RAW|CNF_SEG_OK|CNF_ERR_OK, /* type */ + 0, /* segment length */ + 0 /* checksum */ +}; + +static struct clnp_fixed echo_template = { + ISO8473_CLNP, /* network identifier */ + 0, /* length */ + ISO8473_V1, /* version */ + CLNP_TTL, /* ttl */ + CLNP_EC|CNF_SEG_OK|CNF_ERR_OK, /* type */ + 0, /* segment length */ + 0 /* checksum */ +}; + +static struct clnp_fixed echor_template = { + ISO8473_CLNP, /* network identifier */ + 0, /* length */ + ISO8473_V1, /* version */ + CLNP_TTL, /* ttl */ + CLNP_ECR|CNF_SEG_OK|CNF_ERR_OK, /* type */ + 0, /* segment length */ + 0 /* checksum */ +}; + +#ifdef DECBIT +u_char qos_option[] = {CLNPOVAL_QOS, 1, + CLNPOVAL_GLOBAL|CLNPOVAL_SEQUENCING|CLNPOVAL_LOWDELAY}; +#endif /* DECBIT */ + +int clnp_id = 0; /* id for segmented dgrams */ + +/* + * FUNCTION: clnp_output + * + * PURPOSE: output the data in the mbuf as a clnp datagram + * + * The data specified by m0 is sent as a clnp datagram. + * The mbuf chain m0 will be freed when this routine has + * returned. + * + * If options is non-null, it points to an mbuf which contains + * options to be sent with the datagram. The options must + * be formatted in the mbuf according to clnp rules. Options + * will not be freed. + * + * Datalen specifies the length of the data in m0. + * + * Src and dst are the addresses for the packet. + * + * If route is non-null, it is used as the route for + * the packet. + * + * By default, a DT is sent. However, if flags & CNLP_SEND_ER + * then an ER will be sent. If flags & CLNP_SEND_RAW, then + * the packet will be send as raw clnp. + * + * RETURNS: 0 success + * appropriate error code + * + * SIDE EFFECTS: none + * + * NOTES: + * Flags are interpretated as follows: + * CLNP_NO_SEG - do not allow this pkt to be segmented. + * CLNP_NO_ER - have pkt request ER suppression. + * CLNP_SEND_RAW - send pkt as RAW DT rather than TP DT + * CLNP_NO_CKSUM - don't compute clnp checksum + * CLNP_ECHO - send as ECHO packet + * + * When checking for a cached packet, clnp checks + * that the route taken is still up. It does not + * check that the route is still to the same destination. + * This means that any entity that alters an existing + * route for an isopcb (such as when a redirect arrives) + * must invalidate the clnp cache. It might be perferable + * to have clnp check that the route has the same dest, but + * by avoiding this check, we save a call to iso_addrmatch1. + */ +clnp_output(m0, isop, datalen, flags) +struct mbuf *m0; /* data for the packet */ +struct isopcb *isop; /* iso pcb */ +int datalen; /* number of bytes of data in m0 */ +int flags; /* flags */ +{ + int error = 0; /* return value of function */ + register struct mbuf *m = m0; /* mbuf for clnp header chain */ + register struct clnp_fixed *clnp; /* ptr to fixed part of hdr */ + register caddr_t hoff; /* offset into header */ + int total_len; /* total length of packet */ + struct iso_addr *src; /* ptr to source address */ + struct iso_addr *dst; /* ptr to destination address */ + struct clnp_cache clc; /* storage for cache information */ + struct clnp_cache *clcp = NULL; /* ptr to clc */ + int hdrlen = 0; + + dst = &isop->isop_faddr->siso_addr; + if (isop->isop_laddr == 0) { + struct iso_ifaddr *ia = 0; + clnp_route(dst, &isop->isop_route, flags, 0, &ia); + if (ia == 0 || ia->ia_ifa.ifa_addr->sa_family != AF_ISO) + return (ENETUNREACH); + src = &ia->ia_addr.siso_addr; + } else + src = &isop->isop_laddr->siso_addr; + + IFDEBUG(D_OUTPUT) + printf("clnp_output: to %s", clnp_iso_addrp(dst)); + printf(" from %s of %d bytes\n", clnp_iso_addrp(src), datalen); + printf("\toptions x%x, flags x%x, isop_clnpcache x%x\n", + isop->isop_options, flags, isop->isop_clnpcache); + ENDDEBUG + + if (isop->isop_clnpcache != NULL) { + clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); + } + + /* + * Check if cache is valid ... + */ + IFDEBUG(D_OUTPUT) + printf("clnp_output: ck cache: clcp %x\n", clcp); + if (clcp != NULL) { + printf("\tclc_dst %s\n", clnp_iso_addrp(&clcp->clc_dst)); + printf("\tisop_opts x%x, clc_opts x%x\n", isop->isop_options, + clcp->clc_options); + if (isop->isop_route.ro_rt) + printf("\tro_rt x%x, rt_flags x%x\n", + isop->isop_route.ro_rt, isop->isop_route.ro_rt->rt_flags); + printf("\tflags x%x, clc_flags x%x\n", flags, clcp->clc_flags); + printf("\tclc_hdr x%x\n", clcp->clc_hdr); + } + ENDDEBUG + if ((clcp != NULL) && /* cache exists */ + (isop->isop_options == clcp->clc_options) && /* same options */ + (iso_addrmatch1(dst, &clcp->clc_dst)) && /* dst still same */ + (isop->isop_route.ro_rt != NULL) && /* route exists */ + (isop->isop_route.ro_rt == clcp->clc_rt) && /* and is cached */ + (isop->isop_route.ro_rt->rt_flags & RTF_UP) && /* route still up */ + (flags == clcp->clc_flags) && /* same flags */ + (clcp->clc_hdr != NULL)) { /* hdr mbuf exists */ + /* + * The cache is valid + */ + + IFDEBUG(D_OUTPUT) + printf("clnp_output: using cache\n"); + ENDDEBUG + + m = m_copy(clcp->clc_hdr, 0, (int)M_COPYALL); + if (m == NULL) { + /* + * No buffers left to copy cached packet header. Use + * the cached packet header this time, and + * mark the hdr as vacant + */ + m = clcp->clc_hdr; + clcp->clc_hdr = NULL; + } + m->m_next = m0; /* ASSUMES pkt hdr is 1 mbuf long */ + clnp = mtod(m, struct clnp_fixed *); + } else { + struct clnp_optidx *oidx = NULL; /* index to clnp options */ + + /* + * The cache is not valid. Allocate an mbuf (if necessary) + * to hold cached info. If one is not available, then + * don't bother with the cache + */ + INCSTAT(cns_cachemiss); + if (flags & CLNP_NOCACHE) { + clcp = &clc; + } else { + if (isop->isop_clnpcache == NULL) { + /* + * There is no clnpcache. Allocate an mbuf to hold one + */ + if ((isop->isop_clnpcache = m_get(M_DONTWAIT, MT_HEADER)) + == NULL) { + /* + * No mbufs available. Pretend that we don't want + * caching this time. + */ + IFDEBUG(D_OUTPUT) + printf("clnp_output: no mbufs to allocate to cache\n"); + ENDDEBUG + flags |= CLNP_NOCACHE; + clcp = &clc; + } else { + clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); + } + } else { + /* + * A clnpcache mbuf exists. If the clc_hdr is not null, + * we must free it, as a new one is about to be created. + */ + clcp = mtod(isop->isop_clnpcache, struct clnp_cache *); + if (clcp->clc_hdr != NULL) { + /* + * The clc_hdr is not null but a clnpcache mbuf exists. + * This means that there was a cache, but the existing + * copy of the hdr is no longer valid. Free it now + * before we lose the pointer to it. + */ + IFDEBUG(D_OUTPUT) + printf("clnp_output: freeing old clc_hdr 0x%x\n", + clcp->clc_hdr); + ENDDEBUG + m_free(clcp->clc_hdr); + IFDEBUG(D_OUTPUT) + printf("clnp_output: freed old clc_hdr (done)\n"); + ENDDEBUG + } + } + } + IFDEBUG(D_OUTPUT) + printf("clnp_output: NEW clcp x%x\n",clcp); + ENDDEBUG + bzero((caddr_t)clcp, sizeof(struct clnp_cache)); + + if (isop->isop_optindex) + oidx = mtod(isop->isop_optindex, struct clnp_optidx *); + + /* + * Don't allow packets with security, quality of service, + * priority, or error report options to be sent. + */ + if ((isop->isop_options) && (oidx)) { + if ((oidx->cni_securep) || + (oidx->cni_priorp) || + (oidx->cni_qos_formatp) || + (oidx->cni_er_reason != ER_INVALREAS)) { + IFDEBUG(D_OUTPUT) + printf("clnp_output: pkt dropped - option unsupported\n"); + ENDDEBUG + m_freem(m0); + return(EINVAL); + } + } + + /* + * Don't allow any invalid flags to be set + */ + if ((flags & (CLNP_VFLAGS)) != flags) { + IFDEBUG(D_OUTPUT) + printf("clnp_output: packet dropped - flags unsupported\n"); + ENDDEBUG + INCSTAT(cns_odropped); + m_freem(m0); + return(EINVAL); + } + + /* + * Don't allow funny lengths on dst; src may be zero in which + * case we insert the source address based upon the interface + */ + if ((src->isoa_len > sizeof(struct iso_addr)) || + (dst->isoa_len == 0) || + (dst->isoa_len > sizeof(struct iso_addr))) { + m_freem(m0); + INCSTAT(cns_odropped); + return(ENAMETOOLONG); + } + + /* + * Grab mbuf to contain header + */ + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (m == 0) { + m_freem(m0); + INCSTAT(cns_odropped); + return(ENOBUFS); + } + INCSTAT(cns_sent); + m->m_next = m0; + clnp = mtod(m, struct clnp_fixed *); + clcp->clc_segoff = 0; + + /* + * Fill in all of fixed hdr except lengths and checksum + */ + if (flags & CLNP_SEND_RAW) { + *clnp = raw_template; + } else if (flags & CLNP_ECHO) { + *clnp = echo_template; + } else if (flags & CLNP_ECHOR) { + *clnp = echor_template; + } else { + *clnp = dt_template; + } + if (flags & CLNP_NO_SEG) + clnp->cnf_type &= ~CNF_SEG_OK; + if (flags & CLNP_NO_ER) + clnp->cnf_type &= ~CNF_ERR_OK; + + /* + * Route packet; special case for source rt + */ + if ((isop->isop_options) && CLNPSRCRT_VALID(oidx)) { + IFDEBUG(D_OUTPUT) + printf("clnp_output: calling clnp_srcroute\n"); + ENDDEBUG + error = clnp_srcroute(isop->isop_options, oidx, &isop->isop_route, + &clcp->clc_firsthop, &clcp->clc_ifa, dst); + } else { + IFDEBUG(D_OUTPUT) + ENDDEBUG + error = clnp_route(dst, &isop->isop_route, flags, + &clcp->clc_firsthop, &clcp->clc_ifa); + } + if (error || (clcp->clc_ifa == 0)) { + IFDEBUG(D_OUTPUT) + printf("clnp_output: route failed, errno %d\n", error); + printf("@clcp:\n"); + dump_buf(clcp, sizeof (struct clnp_cache)); + ENDDEBUG + goto bad; + } + clcp->clc_rt = isop->isop_route.ro_rt; /* XXX */ + clcp->clc_ifp = clcp->clc_ifa->ia_ifp; /* XXX */ + + IFDEBUG(D_OUTPUT) + printf("clnp_output: packet routed to %s\n", + clnp_iso_addrp( + &((struct sockaddr_iso *)clcp->clc_firsthop)->siso_addr)); + ENDDEBUG + + /* + * If src address is not yet specified, use address of + * interface. NOTE: this will now update the laddr field in + * the isopcb. Is this desirable? RAH? + */ + if (src->isoa_len == 0) { + src = &(clcp->clc_ifa->ia_addr.siso_addr); + IFDEBUG(D_OUTPUT) + printf("clnp_output: new src %s\n", clnp_iso_addrp(src)); + ENDDEBUG + } + + /* + * Insert the source and destination address, + */ + hoff = (caddr_t)clnp + sizeof(struct clnp_fixed); + CLNP_INSERT_ADDR(hoff, *dst); + CLNP_INSERT_ADDR(hoff, *src); + + /* + * Leave room for the segment part, if segmenting is selected + */ + if (clnp->cnf_type & CNF_SEG_OK) { + clcp->clc_segoff = hoff - (caddr_t)clnp; + hoff += sizeof(struct clnp_segment); + } + + clnp->cnf_hdr_len = m->m_len = (u_char)(hoff - (caddr_t)clnp); + hdrlen = clnp->cnf_hdr_len; + +#ifdef DECBIT + /* + * Add the globally unique QOS (with room for congestion experienced + * bit). I can safely assume that this option is not in the options + * mbuf below because I checked that the option was not specified + * previously + */ + if ((m->m_len + sizeof(qos_option)) < MLEN) { + bcopy((caddr_t)qos_option, hoff, sizeof(qos_option)); + clnp->cnf_hdr_len += sizeof(qos_option); + hdrlen += sizeof(qos_option); + m->m_len += sizeof(qos_option); + } +#endif /* DECBIT */ + + /* + * If an options mbuf is present, concatenate a copy to the hdr mbuf. + */ + if (isop->isop_options) { + struct mbuf *opt_copy = m_copy(isop->isop_options, 0, (int)M_COPYALL); + if (opt_copy == NULL) { + error = ENOBUFS; + goto bad; + } + /* Link in place */ + opt_copy->m_next = m->m_next; + m->m_next = opt_copy; + + /* update size of header */ + clnp->cnf_hdr_len += opt_copy->m_len; + hdrlen += opt_copy->m_len; + } + + if (hdrlen > CLNP_HDR_MAX) { + error = EMSGSIZE; + goto bad; + } + + /* + * Now set up the cache entry in the pcb + */ + if ((flags & CLNP_NOCACHE) == 0) { + if (clcp->clc_hdr = m_copy(m, 0, (int)clnp->cnf_hdr_len)) { + clcp->clc_dst = *dst; + clcp->clc_flags = flags; + clcp->clc_options = isop->isop_options; + } + } + } + /* + * If small enough for interface, send directly + * Fill in segmentation part of hdr if using the full protocol + */ + total_len = clnp->cnf_hdr_len + datalen; + if (clnp->cnf_type & CNF_SEG_OK) { + struct clnp_segment seg_part; /* segment part of hdr */ + seg_part.cng_id = htons(clnp_id++); + seg_part.cng_off = htons(0); + seg_part.cng_tot_len = htons(total_len); + (void) bcopy((caddr_t)&seg_part, (caddr_t) clnp + clcp->clc_segoff, + sizeof(seg_part)); + } + if (total_len <= SN_MTU(clcp->clc_ifp, clcp->clc_rt)) { + HTOC(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, total_len); + m->m_pkthdr.len = total_len; + /* + * Compute clnp checksum (on header only) + */ + if (flags & CLNP_NO_CKSUM) { + HTOC(clnp->cnf_cksum_msb, clnp->cnf_cksum_lsb, 0); + } else { + iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); + } + + IFDEBUG(D_DUMPOUT) + struct mbuf *mdump = m; + printf("clnp_output: sending dg:\n"); + while (mdump != NULL) { + dump_buf(mtod(mdump, caddr_t), mdump->m_len); + mdump = mdump->m_next; + } + ENDDEBUG + + error = SN_OUTPUT(clcp, m); + goto done; + } else { + /* + * Too large for interface; fragment if possible. + */ + error = clnp_fragment(clcp->clc_ifp, m, clcp->clc_firsthop, + total_len, clcp->clc_segoff, flags, clcp->clc_rt); + goto done; + } +bad: + m_freem(m); +done: + if (error) { + clnp_stat.cns_sent--; + clnp_stat.cns_odropped++; + } + return (error); +} + +int clnp_ctloutput() +{ +} diff --git a/sys/netiso/clnp_raw.c b/sys/netiso/clnp_raw.c new file mode 100644 index 0000000..0bc3dba --- /dev/null +++ b/sys/netiso/clnp_raw.c @@ -0,0 +1,352 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_raw.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: clnp_raw.c,v 4.2 88/06/29 14:58:56 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/clnp_raw.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/raw_cb.h> + +#include <netiso/iso.h> +#include <netiso/iso_pcb.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +#include <netiso/tp_user.h> /* XXX -- defines SOL_NETWORK */ + +struct sockproto rclnp_proto = { PF_ISO, 0 }; +/* + * FUNCTION: rclnp_input + * + * PURPOSE: Setup generic address an protocol structures for + * raw input routine, then pass them along with the + * mbuf chain. + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: The protocol field of rclnp_proto is set to zero indicating + * no protocol. + */ +rclnp_input(m, src, dst, hdrlen) +struct mbuf *m; /* ptr to packet */ +struct sockaddr_iso *src; /* ptr to src address */ +struct sockaddr_iso *dst; /* ptr to dest address */ +int hdrlen; /* length (in bytes) of clnp header */ +{ +#ifdef TROLL + if (trollctl.tr_ops & TR_CHUCK) { + m_freem(m); + return; + } +#endif /* TROLL */ + + raw_input(m, &rclnp_proto, (struct sockaddr *)src, (struct sockaddr *)dst); +} + +/* + * FUNCTION: rclnp_output + * + * PURPOSE: Prepare to send a raw clnp packet. Setup src and dest + * addresses, count the number of bytes to send, and + * call clnp_output. + * + * RETURNS: success - 0 + * failure - an appropriate error code + * + * SIDE EFFECTS: + * + * NOTES: + */ +rclnp_output(m0, so) +struct mbuf *m0; /* packet to send */ +struct socket *so; /* socket to send from */ +{ + register struct mbuf *m; /* used to scan a chain */ + int len = 0; /* store length of chain here */ + struct rawisopcb *rp = sotorawisopcb(so); /* ptr to raw cb */ + int error; /* return value of function */ + int flags; /* flags for clnp_output */ + + if (0 == (m0->m_flags & M_PKTHDR)) + return (EINVAL); + /* + * Set up src address. If user has bound socket to an address, use it. + * Otherwise, do not specify src (clnp_output will fill it in). + */ + if (rp->risop_rcb.rcb_laddr) { + if (rp->risop_isop.isop_sladdr.siso_family != AF_ISO) { +bad: + m_freem(m0); + return(EAFNOSUPPORT); + } + } + /* set up dest address */ + if (rp->risop_rcb.rcb_faddr == 0) + goto bad; + rp->risop_isop.isop_sfaddr = + *(struct sockaddr_iso *)rp->risop_rcb.rcb_faddr; + rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr; + + /* get flags and ship it off */ + flags = rp->risop_flags & CLNP_VFLAGS; + + error = clnp_output(m0, &rp->risop_isop, m0->m_pkthdr.len, + flags|CLNP_NOCACHE); + + return (error); +} + +/* + * FUNCTION: rclnp_ctloutput + * + * PURPOSE: Raw clnp socket option processing + * All options are stored inside an mbuf. + * + * RETURNS: success - 0 + * failure - unix error code + * + * SIDE EFFECTS: If the options mbuf does not exist, it the mbuf passed + * is used. + * + * NOTES: + */ +rclnp_ctloutput(op, so, level, optname, m) +int op; /* type of operation */ +struct socket *so; /* ptr to socket */ +int level; /* level of option */ +int optname; /* name of option */ +struct mbuf **m; /* ptr to ptr to option data */ +{ + int error = 0; + register struct rawisopcb *rp = sotorawisopcb(so);/* raw cb ptr */ + + IFDEBUG(D_CTLOUTPUT) + printf("rclnp_ctloutput: op = x%x, level = x%x, name = x%x\n", + op, level, optname); + if (*m != NULL) { + printf("rclnp_ctloutput: %d bytes of mbuf data\n", (*m)->m_len); + dump_buf(mtod((*m), caddr_t), (*m)->m_len); + } + ENDDEBUG + +#ifdef SOL_NETWORK + if (level != SOL_NETWORK) + error = EINVAL; + else switch (op) { +#else + switch (op) { +#endif /* SOL_NETWORK */ + case PRCO_SETOPT: + switch (optname) { + case CLNPOPT_FLAGS: { + u_short usr_flags; + /* + * Insure that the data passed has exactly one short in it + */ + if ((*m == NULL) || ((*m)->m_len != sizeof(short))) { + error = EINVAL; + break; + } + + /* + * Don't allow invalid flags to be set + */ + usr_flags = (*mtod((*m), short *)); + + if ((usr_flags & (CLNP_VFLAGS)) != usr_flags) { + error = EINVAL; + } else + rp->risop_flags |= usr_flags; + + } break; + + case CLNPOPT_OPTS: + if (error = clnp_set_opts(&rp->risop_isop.isop_options, m)) + break; + rp->risop_isop.isop_optindex = m_get(M_WAIT, MT_SOOPTS); + (void) clnp_opt_sanity(rp->risop_isop.isop_options, + mtod(rp->risop_isop.isop_options, caddr_t), + rp->risop_isop.isop_options->m_len, + mtod(rp->risop_isop.isop_optindex, + struct clnp_optidx *)); + break; + } + break; + + case PRCO_GETOPT: +#ifdef notdef + /* commented out to keep hi C quiet */ + switch (optname) { + default: + error = EINVAL; + break; + } +#endif /* notdef */ + break; + default: + error = EINVAL; + break; + } + if (op == PRCO_SETOPT) { + /* note: m_freem does not barf is *m is NULL */ + m_freem(*m); + *m = NULL; + } + + return error; +} + +/*ARGSUSED*/ +clnp_usrreq(so, req, m, nam, control) + register struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register int error = 0; + register struct rawisopcb *rp = sotorawisopcb(so); + + rp = sotorawisopcb(so); + switch (req) { + + case PRU_ATTACH: + if (rp) + panic("rip_attach"); + MALLOC(rp, struct rawisopcb *, sizeof *rp, M_PCB, M_WAITOK); + if (rp == 0) + return (ENOBUFS); + bzero((caddr_t)rp, sizeof *rp); + so->so_pcb = (caddr_t)rp; + break; + + case PRU_DETACH: + if (rp == 0) + panic("rip_detach"); + if (rp->risop_isop.isop_options) + m_freem(rp->risop_isop.isop_options); + if (rp->risop_isop.isop_route.ro_rt) + RTFREE(rp->risop_isop.isop_route.ro_rt); + if (rp->risop_rcb.rcb_laddr) + rp->risop_rcb.rcb_laddr = 0; + /* free clnp cached hdr if necessary */ + if (rp->risop_isop.isop_clnpcache != NULL) { + struct clnp_cache *clcp = + mtod(rp->risop_isop.isop_clnpcache, struct clnp_cache *); + if (clcp->clc_hdr != NULL) { + m_free(clcp->clc_hdr); + } + m_free(rp->risop_isop.isop_clnpcache); + } + if (rp->risop_isop.isop_optindex != NULL) + m_free(rp->risop_isop.isop_optindex); + + break; + + case PRU_BIND: + { + struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); + + if (nam->m_len != sizeof(*addr)) + return (EINVAL); + if ((ifnet == 0) || + (addr->siso_family != AF_ISO) || + (addr->siso_addr.isoa_len && + ifa_ifwithaddr((struct sockaddr *)addr) == 0)) + return (EADDRNOTAVAIL); + rp->risop_isop.isop_sladdr = *addr; + rp->risop_rcb.rcb_laddr = (struct sockaddr *) + (rp->risop_isop.isop_laddr = &rp->risop_isop.isop_sladdr); + return (0); + } + case PRU_CONNECT: + { + struct sockaddr_iso *addr = mtod(nam, struct sockaddr_iso *); + + if ((nam->m_len > sizeof(*addr)) || (addr->siso_len > sizeof(*addr))) + return (EINVAL); + if (ifnet == 0) + return (EADDRNOTAVAIL); + if (addr->siso_family != AF_ISO) + rp->risop_isop.isop_sfaddr = *addr; + rp->risop_rcb.rcb_faddr = (struct sockaddr *) + (rp->risop_isop.isop_faddr = &rp->risop_isop.isop_sfaddr); + soisconnected(so); + return (0); + } + } + error = raw_usrreq(so, req, m, nam, control); + + if (error && req == PRU_ATTACH && so->so_pcb) + free((caddr_t)rp, M_PCB); + return (error); +} diff --git a/sys/netiso/clnp_stat.h b/sys/netiso/clnp_stat.h new file mode 100644 index 0000000..07cd72c --- /dev/null +++ b/sys/netiso/clnp_stat.h @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_stat.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_stat.h,v 5.1 89/02/09 16:20:42 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_stat.h,v $ */ + + +#ifndef __CLNP_STAT__ +#define __CLNP_STAT__ + +struct clnp_stat { + int cns_total; /* total pkts received */ + int cns_toosmall; /* fixed part of header too small */ + int cns_badhlen; /* header length is not reasonable */ + int cns_badcsum; /* checksum on packet failed */ + int cns_badaddr; /* address fields were not reasonable */ + int cns_badvers; /* incorrect version */ + int cns_noseg; /* segment information forgotten */ + int cns_noproto; /* incorrect protocol id */ + int cns_delivered; /* packets consumed by protocol */ + int cns_ttlexpired; /* ttl has expired */ + int cns_forward; /* forwarded packets */ + int cns_sent; /* total packets sent */ + int cns_odropped; /* o.k. packets discarded, e.g. ENOBUFS */ + int cns_cantforward; /* non-forwarded packets */ + int cns_fragmented; /* packets fragmented */ + int cns_fragments; /* fragments received */ + int cns_fragdropped; /* fragments discarded */ + int cns_fragtimeout; /* fragments timed out */ + int cns_ofragments; /* fragments generated */ + int cns_cantfrag; /* fragmentation prohibited */ + int cns_reassembled; /* packets reconstructed */ + int cns_cachemiss; /* cache misses */ + int cns_congest_set; /* congestion experienced bit set */ + int cns_congest_rcvd; /* congestion experienced bit received */ + int cns_er_inhist[CLNP_ERRORS + 1]; + int cns_er_outhist[CLNP_ERRORS + 1]; +} clnp_stat ; + +#ifdef INCSTAT +#undef INCSTAT +#endif /* INCSTAT */ +#define INCSTAT(x) clnp_stat./**/x/**/++ + +#endif /* __CLNP_STAT__ */ diff --git a/sys/netiso/clnp_subr.c b/sys/netiso/clnp_subr.c new file mode 100644 index 0000000..c877811 --- /dev/null +++ b/sys/netiso/clnp_subr.c @@ -0,0 +1,658 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_subr.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: /var/src/sys/netiso/RCS/clnp_subr.c,v 5.1 89/02/09 16:20:46 hagens Exp $ */ +/* $Source: /var/src/sys/netiso/RCS/clnp_subr.c,v $ */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/route.h> +#include <net/if_dl.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_snpac.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +/* + * FUNCTION: clnp_data_ck + * + * PURPOSE: Check that the amount of data in the mbuf chain is + * at least as much as the clnp header would have us + * expect. Trim mbufs if longer than expected, drop + * packet if shorter than expected. + * + * RETURNS: success - ptr to mbuf chain + * failure - 0 + * + * SIDE EFFECTS: + * + * NOTES: + */ +struct mbuf * +clnp_data_ck(m, length) +register struct mbuf *m; /* ptr to mbuf chain containing hdr & data */ +int length; /* length (in bytes) of packet */ + { + register int len; /* length of data */ + register struct mbuf *mhead; /* ptr to head of chain */ + + len = -length; + mhead = m; + for (;;) { + len += m->m_len; + if (m->m_next == 0) + break; + m = m->m_next; + } + if (len != 0) { + if (len < 0) { + INCSTAT(cns_toosmall); + clnp_discard(mhead, GEN_INCOMPLETE); + return 0; + } + if (len <= m->m_len) + m->m_len -= len; + else + m_adj(mhead, -len); + } + return mhead; +} + +#ifdef notdef +/* + * FUNCTION: clnp_extract_addr + * + * PURPOSE: Extract the source and destination address from the + * supplied buffer. Place them in the supplied address buffers. + * If insufficient data is supplied, then fail. + * + * RETURNS: success - Address of first byte in the packet past + * the address part. + * failure - 0 + * + * SIDE EFFECTS: + * + * NOTES: + */ +caddr_t +clnp_extract_addr(bufp, buflen, srcp, destp) +caddr_t bufp; /* ptr to buffer containing addresses */ +int buflen; /* length of buffer */ +register struct iso_addr *srcp; /* ptr to source address buffer */ +register struct iso_addr *destp; /* ptr to destination address buffer */ + { + int len; /* argument to bcopy */ + + /* + * check that we have enough data. Plus1 is for length octet + */ + if ((u_char)*bufp + 1 > buflen) { + return((caddr_t)0); + } + len = destp->isoa_len = (u_char)*bufp++; + (void) bcopy(bufp, (caddr_t)destp, len); + buflen -= len; + bufp += len; + + /* + * check that we have enough data. Plus1 is for length octet + */ + if ((u_char)*bufp + 1 > buflen) { + return((caddr_t)0); + } + len = srcp->isoa_len = (u_char)* bufp++; + (void) bcopy(bufp, (caddr_t)srcp, len); + bufp += len; + + /* + * Insure that the addresses make sense + */ + if (iso_ck_addr(srcp) && iso_ck_addr(destp)) + return bufp; + else + return (caddr_t) 0; +} +#endif /* notdef */ + +/* + * FUNCTION: clnp_ours + * + * PURPOSE: Decide whether the supplied packet is destined for + * us, or that it should be forwarded on. + * + * RETURNS: packet is for us - 1 + * packet is not for us - 0 + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_ours(dst) +register struct iso_addr *dst; /* ptr to destination address */ +{ + register struct iso_ifaddr *ia; /* scan through interface addresses */ + + for (ia = iso_ifaddr; ia; ia = ia->ia_next) { + IFDEBUG(D_ROUTE) + printf("clnp_ours: ia_sis x%x, dst x%x\n", &ia->ia_addr, + dst); + ENDDEBUG + /* + * XXX Warning: + * We are overloading siso_tlen in the if's address, as an nsel length. + */ + if (dst->isoa_len == ia->ia_addr.siso_nlen && + bcmp((caddr_t)ia->ia_addr.siso_addr.isoa_genaddr, + (caddr_t)dst->isoa_genaddr, + ia->ia_addr.siso_nlen - ia->ia_addr.siso_tlen) == 0) + return 1; + } + return 0; +} + +/* Dec bit set if ifp qlen is greater than congest_threshold */ +int congest_threshold = 0; + +/* + * FUNCTION: clnp_forward + * + * PURPOSE: Forward the datagram passed + * clnpintr guarantees that the header will be + * contigious (a cluster mbuf will be used if necessary). + * + * If oidx is NULL, no options are present. + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_forward(m, len, dst, oidx, seg_off, inbound_shp) +struct mbuf *m; /* pkt to forward */ +int len; /* length of pkt */ +struct iso_addr *dst; /* destination address */ +struct clnp_optidx *oidx; /* option index */ +int seg_off;/* offset of segmentation part */ +struct snpa_hdr *inbound_shp; /* subnetwork header of inbound packet */ +{ + struct clnp_fixed *clnp; /* ptr to fixed part of header */ + int error; /* return value of route function */ + struct sockaddr *next_hop; /* next hop for dgram */ + struct ifnet *ifp; /* ptr to outgoing interface */ + struct iso_ifaddr *ia = 0;/* ptr to iso name for ifp */ + struct route_iso route; /* filled in by clnp_route */ + extern int iso_systype; + + clnp = mtod(m, struct clnp_fixed *); + bzero((caddr_t)&route, sizeof(route)); /* MUST be done before "bad:" */ + + /* + * Don't forward multicast or broadcast packets + */ + if ((inbound_shp) && (IS_MULTICAST(inbound_shp->snh_dhost))) { + IFDEBUG(D_FORWARD) + printf("clnp_forward: dropping multicast packet\n"); + ENDDEBUG + clnp->cnf_type &= ~CNF_ERR_OK; /* so we don't generate an ER */ + clnp_discard(m, 0); + INCSTAT(cns_cantforward); + goto done; + } + + IFDEBUG(D_FORWARD) + printf("clnp_forward: %d bytes, to %s, options x%x\n", len, + clnp_iso_addrp(dst), oidx); + ENDDEBUG + + /* + * Decrement ttl, and if zero drop datagram + * Can't compare ttl as less than zero 'cause its a unsigned + */ + if ((clnp->cnf_ttl == 0) || (--clnp->cnf_ttl == 0)) { + IFDEBUG(D_FORWARD) + printf("clnp_forward: discarding datagram because ttl is zero\n"); + ENDDEBUG + INCSTAT(cns_ttlexpired); + clnp_discard(m, TTL_EXPTRANSIT); + goto done; + } + /* + * Route packet; special case for source rt + */ + if CLNPSRCRT_VALID(oidx) { + /* + * Update src route first + */ + clnp_update_srcrt(m, oidx); + error = clnp_srcroute(m, oidx, &route, &next_hop, &ia, dst); + } else { + error = clnp_route(dst, &route, 0, &next_hop, &ia); + } + if (error || ia == 0) { + IFDEBUG(D_FORWARD) + printf("clnp_forward: can't route packet (errno %d)\n", error); + ENDDEBUG + clnp_discard(m, ADDR_DESTUNREACH); + INCSTAT(cns_cantforward); + goto done; + } + ifp = ia->ia_ifp; + + IFDEBUG(D_FORWARD) + printf("clnp_forward: packet routed to %s\n", + clnp_iso_addrp(&((struct sockaddr_iso *)next_hop)->siso_addr)); + ENDDEBUG + + INCSTAT(cns_forward); + + /* + * If we are an intermediate system and + * we are routing outbound on the same ifp that the packet + * arrived upon, and we know the next hop snpa, + * then generate a redirect request + */ + if ((iso_systype & SNPA_IS) && (inbound_shp) && + (ifp == inbound_shp->snh_ifp)) + esis_rdoutput(inbound_shp, m, oidx, dst, route.ro_rt); + /* + * If options are present, update them + */ + if (oidx) { + struct iso_addr *mysrc = &ia->ia_addr.siso_addr; + if (mysrc == NULL) { + clnp_discard(m, ADDR_DESTUNREACH); + INCSTAT(cns_cantforward); + clnp_stat.cns_forward--; + goto done; + } else { + (void) clnp_dooptions(m, oidx, ifp, mysrc); + } + } + +#ifdef DECBIT + if (ifp->if_snd.ifq_len > congest_threshold) { + /* + * Congestion! Set the Dec Bit and thank Dave Oran + */ + IFDEBUG(D_FORWARD) + printf("clnp_forward: congestion experienced\n"); + ENDDEBUG + if ((oidx) && (oidx->cni_qos_formatp)) { + caddr_t qosp = CLNP_OFFTOOPT(m, oidx->cni_qos_formatp); + u_char qos = *qosp; + IFDEBUG(D_FORWARD) + printf("clnp_forward: setting congestion bit (qos x%x)\n", qos); + ENDDEBUG + if ((qos & CLNPOVAL_GLOBAL) == CLNPOVAL_GLOBAL) { + qos |= CLNPOVAL_CONGESTED; + INCSTAT(cns_congest_set); + *qosp = qos; + } + } + } +#endif /* DECBIT */ + + /* + * Dispatch the datagram if it is small enough, otherwise fragment + */ + if (len <= SN_MTU(ifp, route.ro_rt)) { + iso_gen_csum(m, CLNP_CKSUM_OFF, (int)clnp->cnf_hdr_len); + (void) (*ifp->if_output)(ifp, m, next_hop, route.ro_rt); + } else { + (void) clnp_fragment(ifp, m, next_hop, len, seg_off, /* flags */0, route.ro_rt); + } + +done: + /* + * Free route + */ + if (route.ro_rt != NULL) { + RTFREE(route.ro_rt); + } +} + +#ifdef notdef +/* + * FUNCTION: clnp_insert_addr + * + * PURPOSE: Insert the address part into a clnp datagram. + * + * RETURNS: Address of first byte after address part in datagram. + * + * SIDE EFFECTS: + * + * NOTES: Assume that there is enough space for the address part. + */ +caddr_t +clnp_insert_addr(bufp, srcp, dstp) +caddr_t bufp; /* address of where addr part goes */ +register struct iso_addr *srcp; /* ptr to src addr */ +register struct iso_addr *dstp; /* ptr to dst addr */ +{ + *bufp++ = dstp->isoa_len; + (void) bcopy((caddr_t)dstp, bufp, dstp->isoa_len); + bufp += dstp->isoa_len; + + *bufp++ = srcp->isoa_len; + (void) bcopy((caddr_t)srcp, bufp, srcp->isoa_len); + bufp += srcp->isoa_len; + + return bufp; +} + +#endif /* notdef */ + +/* + * FUNCTION: clnp_route + * + * PURPOSE: Route a clnp datagram to the first hop toward its + * destination. In many cases, the first hop will be + * the destination. The address of a route + * is specified. If a routing entry is present in + * that route, and it is still up to the same destination, + * then no further action is necessary. Otherwise, a + * new routing entry will be allocated. + * + * RETURNS: route found - 0 + * unix error code + * + * SIDE EFFECTS: + * + * NOTES: It is up to the caller to free the routing entry + * allocated in route. + */ +clnp_route(dst, ro, flags, first_hop, ifa) + struct iso_addr *dst; /* ptr to datagram destination */ + register struct route_iso *ro; /* existing route structure */ + int flags; /* flags for routing */ + struct sockaddr **first_hop; /* result: fill in with ptr to firsthop */ + struct iso_ifaddr **ifa; /* result: fill in with ptr to interface */ +{ + if (flags & SO_DONTROUTE) { + struct iso_ifaddr *ia; + + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = 0; + } + bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); + bcopy((caddr_t)dst, (caddr_t)&ro->ro_dst.siso_addr, + 1 + (unsigned)dst->isoa_len); + ro->ro_dst.siso_family = AF_ISO; + ro->ro_dst.siso_len = sizeof(ro->ro_dst); + ia = iso_localifa(&ro->ro_dst); + if (ia == 0) + return EADDRNOTAVAIL; + if (ifa) + *ifa = ia; + if (first_hop) + *first_hop = (struct sockaddr *)&ro->ro_dst; + return 0; + } + /* + * If there is a cached route, check that it is still up and to + * the same destination. If not, free it and try again. + */ + if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 || + (Bcmp(ro->ro_dst.siso_data, dst->isoa_genaddr, dst->isoa_len)))) { + IFDEBUG(D_ROUTE) + printf("clnp_route: freeing old route: ro->ro_rt 0x%x\n", + ro->ro_rt); + printf("clnp_route: old route refcnt: 0x%x\n", + ro->ro_rt->rt_refcnt); + ENDDEBUG + + /* free old route entry */ + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } else { + IFDEBUG(D_ROUTE) + printf("clnp_route: OK route exists\n"); + ENDDEBUG + } + + if (ro->ro_rt == 0) { + /* set up new route structure */ + bzero((caddr_t)&ro->ro_dst, sizeof(ro->ro_dst)); + ro->ro_dst.siso_len = sizeof(ro->ro_dst); + ro->ro_dst.siso_family = AF_ISO; + Bcopy(dst, &ro->ro_dst.siso_addr, 1 + dst->isoa_len); + /* allocate new route */ + IFDEBUG(D_ROUTE) + printf("clnp_route: allocating new route to %s\n", + clnp_iso_addrp(dst)); + ENDDEBUG + rtalloc((struct route *)ro); + } + if (ro->ro_rt == 0) + return(ENETUNREACH); /* rtalloc failed */ + ro->ro_rt->rt_use++; + if (ifa) + if ((*ifa = (struct iso_ifaddr *)ro->ro_rt->rt_ifa) == 0) + panic("clnp_route"); + if (first_hop) { + if (ro->ro_rt->rt_flags & RTF_GATEWAY) + *first_hop = ro->ro_rt->rt_gateway; + else + *first_hop = (struct sockaddr *)&ro->ro_dst; + } + return(0); +} + +/* + * FUNCTION: clnp_srcroute + * + * PURPOSE: Source route the datagram. If complete source + * routing is specified but not possible, then + * return an error. If src routing is terminated, then + * try routing on destination. + * Usage of first_hop, + * ifp, and error return is identical to clnp_route. + * + * RETURNS: 0 or unix error code + * + * SIDE EFFECTS: + * + * NOTES: Remember that option index pointers are really + * offsets from the beginning of the mbuf. + */ +clnp_srcroute(options, oidx, ro, first_hop, ifa, final_dst) +struct mbuf *options; /* ptr to options */ +struct clnp_optidx *oidx; /* index to options */ +struct route_iso *ro; /* route structure */ +struct sockaddr **first_hop; /* RETURN: fill in with ptr to firsthop */ +struct iso_ifaddr **ifa; /* RETURN: fill in with ptr to interface */ +struct iso_addr *final_dst; /* final destination */ +{ + struct iso_addr dst; /* first hop specified by src rt */ + int error = 0; /* return code */ + + /* + * Check if we have run out of routes + * If so, then try to route on destination. + */ + if CLNPSRCRT_TERM(oidx, options) { + dst.isoa_len = final_dst->isoa_len; + bcopy(final_dst->isoa_genaddr, dst.isoa_genaddr, dst.isoa_len); + } else { + /* + * setup dst based on src rt specified + */ + dst.isoa_len = CLNPSRCRT_CLEN(oidx, options); + bcopy(CLNPSRCRT_CADDR(oidx, options), dst.isoa_genaddr, dst.isoa_len); + } + + /* + * try to route it + */ + error = clnp_route(&dst, ro, 0, first_hop, ifa); + if (error != 0) + return error; + + /* + * If complete src rt, first hop must be equal to dst + */ + if ((CLNPSRCRT_TYPE(oidx, options) == CLNPOVAL_COMPRT) && + (!iso_addrmatch1(&(*(struct sockaddr_iso **)first_hop)->siso_addr,&dst))){ + IFDEBUG(D_OPTIONS) + printf("clnp_srcroute: complete src route failed\n"); + ENDDEBUG + return EHOSTUNREACH; /* RAH? would like ESRCRTFAILED */ + } + + return error; +} + +/* + * FUNCTION: clnp_echoreply + * + * PURPOSE: generate an echo reply packet and transmit + * + * RETURNS: result of clnp_output + * + * SIDE EFFECTS: + */ +clnp_echoreply(ec_m, ec_len, ec_src, ec_dst, ec_oidxp) +struct mbuf *ec_m; /* echo request */ +int ec_len; /* length of ec */ +struct sockaddr_iso *ec_src; /* src of ec */ +struct sockaddr_iso *ec_dst; /* destination of ec (i.e., us) */ +struct clnp_optidx *ec_oidxp; /* options index to ec packet */ +{ + struct isopcb isopcb; + int flags = CLNP_NOCACHE|CLNP_ECHOR; + int ret; + + /* fill in fake isopcb to pass to output function */ + bzero(&isopcb, sizeof(isopcb)); + isopcb.isop_laddr = ec_dst; + isopcb.isop_faddr = ec_src; + + /* forget copying the options for now. If implemented, need only + * copy record route option, but it must be reset to zero length */ + + ret = clnp_output(ec_m, &isopcb, ec_len, flags); + + IFDEBUG(D_OUTPUT) + printf("clnp_echoreply: output returns %d\n", ret); + ENDDEBUG + return ret; +} + +/* + * FUNCTION: clnp_badmtu + * + * PURPOSE: print notice of route with mtu not initialized. + * + * RETURNS: mtu of ifp. + * + * SIDE EFFECTS: prints notice, slows down system. + */ +clnp_badmtu(ifp, rt, line, file) +struct ifnet *ifp; /* outgoing interface */ +struct rtentry *rt; /* dst route */ +int line; /* where the dirty deed occured */ +char *file; /* where the dirty deed occured */ +{ + printf("sending on route 0x%x with no mtu, line %d of file %s\n", + rt, line, file); +#ifdef ARGO_DEBUG + printf("route dst is "); + dump_isoaddr(rt_key(rt)); +#endif + return ifp->if_mtu; +} + +/* + * FUNCTION: clnp_ypocb - backwards bcopy + * + * PURPOSE: bcopy starting at end of src rather than beginning. + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: No attempt has been made to make this efficient + */ +clnp_ypocb(from, to, len) +caddr_t from; /* src buffer */ +caddr_t to; /* dst buffer */ +u_int len; /* number of bytes */ +{ + while (len--) + *(to + len) = *(from + len); +} +#endif /* ISO */ diff --git a/sys/netiso/clnp_timer.c b/sys/netiso/clnp_timer.c new file mode 100644 index 0000000..718d530 --- /dev/null +++ b/sys/netiso/clnp_timer.c @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)clnp_timer.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: clnp_timer.c,v 4.2 88/06/29 14:59:05 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/clnp_timer.c,v $ */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/argo_debug.h> + +extern struct clnp_fragl *clnp_frags; + +/* + * FUNCTION: clnp_freefrags + * + * PURPOSE: Free the resources associated with a fragment + * + * RETURNS: pointer to next fragment in list of fragments + * + * SIDE EFFECTS: + * + * NOTES: + * TODO: send ER back to source + */ +struct clnp_fragl * +clnp_freefrags(cfh) +register struct clnp_fragl *cfh; /* fragment header to delete */ +{ + struct clnp_fragl *next = cfh->cfl_next; + struct clnp_frag *cf; + + /* free any frags hanging around */ + cf = cfh->cfl_frags; + while (cf != NULL) { + struct clnp_frag *cf_next = cf->cfr_next; + INCSTAT(cns_fragdropped); + m_freem(cf->cfr_data); + cf = cf_next; + } + + /* free the copy of the header */ + INCSTAT(cns_fragdropped); + m_freem(cfh->cfl_orighdr); + + if (clnp_frags == cfh) { + clnp_frags = cfh->cfl_next; + } else { + struct clnp_fragl *scan; + + for (scan = clnp_frags; scan != NULL; scan = scan->cfl_next) { + if (scan->cfl_next == cfh) { + scan->cfl_next = cfh->cfl_next; + break; + } + } + } + + /* free the fragment header */ + m_freem(dtom(cfh)); + + return(next); +} + +/* + * FUNCTION: clnp_slowtimo + * + * PURPOSE: clnp timer processing; if the ttl expires on a + * packet on the reassembly queue, discard it. + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: + */ +clnp_slowtimo() +{ + register struct clnp_fragl *cfh = clnp_frags; + int s = splnet(); + + while (cfh != NULL) { + if (--cfh->cfl_ttl == 0) { + cfh = clnp_freefrags(cfh); + INCSTAT(cns_fragtimeout); + } else { + cfh = cfh->cfl_next; + } + } + splx(s); +} + +/* + * FUNCTION: clnp_drain + * + * PURPOSE: drain off all datagram fragments + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: + * TODO: should send back ER + */ +clnp_drain() +{ + register struct clnp_fragl *cfh = clnp_frags; + + while (cfh != NULL) + cfh = clnp_freefrags(cfh); +} diff --git a/sys/netiso/cltp_usrreq.c b/sys/netiso/cltp_usrreq.c new file mode 100644 index 0000000..93f8d1c --- /dev/null +++ b/sys/netiso/cltp_usrreq.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cltp_usrreq.c 8.1 (Berkeley) 6/10/93 + */ + +#ifndef CLTPOVAL_SRC /* XXX -- till files gets changed */ +#include <sys/param.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> +#include <netiso/clnp.h> +#include <netiso/cltp_var.h> +#endif + +/* + * CLTP protocol implementation. + * Per ISO 8602, December, 1987. + */ +cltp_init() +{ + + cltb.isop_next = cltb.isop_prev = &cltb; +} + +int cltp_cksum = 1; + + +/* ARGUSED */ +cltp_input(m0, srcsa, dstsa, cons_channel, output) + struct mbuf *m0; + struct sockaddr *srcsa, *dstsa; + u_int cons_channel; + int (*output)(); +{ + register struct isopcb *isop; + register struct mbuf *m = m0; + register u_char *up = mtod(m, u_char *); + register struct sockaddr_iso *src = (struct sockaddr_iso *)srcsa; + int len, hdrlen = *up + 1, dlen = 0; + u_char *uplim = up + hdrlen; + caddr_t dtsap; + + for (len = 0; m; m = m->m_next) + len += m->m_len; + up += 2; /* skip header */ + while (up < uplim) switch (*up) { /* process options */ + case CLTPOVAL_SRC: + src->siso_tlen = up[1]; + src->siso_len = up[1] + TSEL(src) - (caddr_t)src; + if (src->siso_len < sizeof(*src)) + src->siso_len = sizeof(*src); + else if (src->siso_len > sizeof(*src)) { + MGET(m, M_DONTWAIT, MT_SONAME); + if (m == 0) + goto bad; + m->m_len = src->siso_len; + src = mtod(m, struct sockaddr_iso *); + bcopy((caddr_t)srcsa, (caddr_t)src, srcsa->sa_len); + } + bcopy((caddr_t)up + 2, TSEL(src), up[1]); + up += 2 + src->siso_tlen; + continue; + + case CLTPOVAL_DST: + dtsap = 2 + (caddr_t)up; + dlen = up[1]; + up += 2 + dlen; + continue; + + case CLTPOVAL_CSM: + if (iso_check_csum(m0, len)) { + cltpstat.cltps_badsum++; + goto bad; + } + up += 4; + continue; + + default: + printf("clts: unknown option (%x)\n", up[0]); + cltpstat.cltps_hdrops++; + goto bad; + } + if (dlen == 0 || src->siso_tlen == 0) + goto bad; + for (isop = cltb.isop_next;; isop = isop->isop_next) { + if (isop == &cltb) { + cltpstat.cltps_noport++; + goto bad; + } + if (isop->isop_laddr && + bcmp(TSEL(isop->isop_laddr), dtsap, dlen) == 0) + break; + } + m = m0; + m->m_len -= hdrlen; + m->m_data += hdrlen; + if (sbappendaddr(&isop->isop_socket->so_rcv, (struct sockaddr *)src, + m, (struct mbuf *)0) == 0) + goto bad; + cltpstat.cltps_ipackets++; + sorwakeup(isop->isop_socket); + m0 = 0; +bad: + if (src != (struct sockaddr_iso *)srcsa) + m_freem(dtom(src)); + if (m0) + m_freem(m0); + return 0; +} + +/* + * Notify a cltp user of an asynchronous error; + * just wake up so that he can collect error status. + */ +cltp_notify(isop) + register struct isopcb *isop; +{ + + sorwakeup(isop->isop_socket); + sowwakeup(isop->isop_socket); +} + +cltp_ctlinput(cmd, sa) + int cmd; + struct sockaddr *sa; +{ + extern u_char inetctlerrmap[]; + struct sockaddr_iso *siso; + int iso_rtchange(); + + if ((unsigned)cmd > PRC_NCMDS) + return; + if (sa->sa_family != AF_ISO && sa->sa_family != AF_CCITT) + return; + siso = (struct sockaddr_iso *)sa; + if (siso == 0 || siso->siso_nlen == 0) + return; + + switch (cmd) { + case PRC_ROUTEDEAD: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + iso_pcbnotify(&cltb, siso, + (int)inetctlerrmap[cmd], iso_rtchange); + break; + + default: + if (inetctlerrmap[cmd] == 0) + return; /* XXX */ + iso_pcbnotify(&cltb, siso, (int)inetctlerrmap[cmd], + cltp_notify); + } +} + +cltp_output(isop, m) + register struct isopcb *isop; + register struct mbuf *m; +{ + register int len; + register struct sockaddr_iso *siso; + int hdrlen, error = 0, docsum; + register u_char *up; + + if (isop->isop_laddr == 0 || isop->isop_faddr == 0) { + error = ENOTCONN; + goto bad; + } + /* + * Calculate data length and get a mbuf for CLTP header. + */ + hdrlen = 2 + 2 + isop->isop_laddr->siso_tlen + + 2 + isop->isop_faddr->siso_tlen; + if (docsum = /*isop->isop_flags & CLNP_NO_CKSUM*/ cltp_cksum) + hdrlen += 4; + M_PREPEND(m, hdrlen, M_WAIT); + len = m->m_pkthdr.len; + /* + * Fill in mbuf with extended CLTP header + */ + up = mtod(m, u_char *); + up[0] = hdrlen - 1; + up[1] = UD_TPDU_type; + up[2] = CLTPOVAL_SRC; + up[3] = (siso = isop->isop_laddr)->siso_tlen; + up += 4; + bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); + up += siso->siso_tlen; + up[0] = CLTPOVAL_DST; + up[1] = (siso = isop->isop_faddr)->siso_tlen; + up += 2; + bcopy(TSEL(siso), (caddr_t)up, siso->siso_tlen); + /* + * Stuff checksum and output datagram. + */ + if (docsum) { + up += siso->siso_tlen; + up[0] = CLTPOVAL_CSM; + up[1] = 2; + iso_gen_csum(m, 2 + up - mtod(m, u_char *), len); + } + cltpstat.cltps_opackets++; + return (tpclnp_output(isop, m, len, !docsum)); +bad: + m_freem(m); + return (error); +} + +u_long cltp_sendspace = 9216; /* really max datagram size */ +u_long cltp_recvspace = 40 * (1024 + sizeof(struct sockaddr_iso)); + /* 40 1K datagrams */ + + +/*ARGSUSED*/ +cltp_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register struct isopcb *isop = sotoisopcb(so); + int s, error = 0; + + if (req == PRU_CONTROL) + return (iso_control(so, (int)m, (caddr_t)nam, + (struct ifnet *)control)); + if ((isop == NULL && req != PRU_ATTACH) || + (control && control->m_len)) { + error = EINVAL; + goto release; + } + switch (req) { + + case PRU_ATTACH: + if (isop != NULL) { + error = EINVAL; + break; + } + error = iso_pcballoc(so, &cltb); + if (error) + break; + error = soreserve(so, cltp_sendspace, cltp_recvspace); + if (error) + break; + break; + + case PRU_DETACH: + iso_pcbdetach(isop); + break; + + case PRU_BIND: + error = iso_pcbbind(isop, nam); + break; + + case PRU_LISTEN: + error = EOPNOTSUPP; + break; + + case PRU_CONNECT: + if (isop->isop_faddr) { + error = EISCONN; + break; + } + error = iso_pcbconnect(isop, nam); + if (error == 0) + soisconnected(so); + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; + break; + + case PRU_ACCEPT: + error = EOPNOTSUPP; + break; + + case PRU_DISCONNECT: + if (isop->isop_faddr == 0) { + error = ENOTCONN; + break; + } + iso_pcbdisconnect(isop); + so->so_state &= ~SS_ISCONNECTED; /* XXX */ + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + if (nam) { + if (isop->isop_faddr) { + error = EISCONN; + break; + } + /* + * Must block input while temporarily connected. + */ + s = splnet(); + error = iso_pcbconnect(isop, nam); + if (error) { + splx(s); + break; + } + } else { + if (isop->isop_faddr == 0) { + error = ENOTCONN; + break; + } + } + error = cltp_output(isop, m); + m = 0; + if (nam) { + iso_pcbdisconnect(isop); + splx(s); + } + break; + + case PRU_ABORT: + soisdisconnected(so); + iso_pcbdetach(isop); + break; + + case PRU_SOCKADDR: + if (isop->isop_laddr) + bcopy((caddr_t)isop->isop_laddr, mtod(m, caddr_t), + nam->m_len = isop->isop_laddr->siso_len); + break; + + case PRU_PEERADDR: + if (isop->isop_faddr) + bcopy((caddr_t)isop->isop_faddr, mtod(m, caddr_t), + nam->m_len = isop->isop_faddr->siso_len); + break; + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + case PRU_SENDOOB: + case PRU_FASTTIMO: + case PRU_SLOWTIMO: + case PRU_PROTORCV: + case PRU_PROTOSEND: + error = EOPNOTSUPP; + break; + + case PRU_RCVD: + case PRU_RCVOOB: + return (EOPNOTSUPP); /* do not free mbuf's */ + + default: + panic("cltp_usrreq"); + } +release: + if (control != NULL) + m_freem(control); + if (m != NULL) + m_freem(m); + return (error); +} diff --git a/sys/netiso/cltp_var.h b/sys/netiso/cltp_var.h new file mode 100644 index 0000000..b4e08f2 --- /dev/null +++ b/sys/netiso/cltp_var.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cltp_var.h 8.1 (Berkeley) 6/10/93 + */ + +#define UD_TPDU_type 0x40 /* packet type */ + +#define CLTPOVAL_SRC 0xc1 /* Source TSAP -- required */ +#define CLTPOVAL_DST 0xc2 /* Destination TSAP -- required */ +#define CLTPOVAL_CSM 0xc3 /* Checksum parameter -- optional */ + +struct cltpstat { + int cltps_hdrops; + int cltps_badsum; + int cltps_badlen; + int cltps_noport; + int cltps_ipackets; + int cltps_opackets; +}; + +#ifdef KERNEL +struct isopcb cltb; +struct cltpstat cltpstat; +#endif diff --git a/sys/netiso/cons.h b/sys/netiso/cons.h new file mode 100644 index 0000000..b0739de --- /dev/null +++ b/sys/netiso/cons.h @@ -0,0 +1,92 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cons.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: cons.h,v 4.4 88/09/09 19:01:28 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/cons.h,v $ + * + * interface between TP and CONS + */ + +#define CONSOPT_X25CRUD 0x01 /* set x.25 call request user data */ + +struct dte_addr { + u_char dtea_addr[7]; + u_char dtea_niblen; +}; + +#ifdef KERNEL + +#define CONN_OPEN 0x33 +#define CONN_CONFIRM 0x30 +#define CONN_REFUSE 0x31 +#define CONN_CLOSE 0x32 + +#define CONS_IS_DGM 0x1 +#define CONS_NOT_DGM 0x0 + +#ifndef PRC_NCMDS +#include <sys/protosw.h> +#endif /* PRC_NCMDS */ + +#define PRC_CONS_SEND_DONE 2 /* something unused in protosw.h */ + +#endif /* KERNEL */ diff --git a/sys/netiso/cons_pcb.h b/sys/netiso/cons_pcb.h new file mode 100644 index 0000000..b8adc37 --- /dev/null +++ b/sys/netiso/cons_pcb.h @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cons_pcb.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: cons_pcb.h,v 4.2 88/06/29 14:59:08 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/cons_pcb.h,v $ */ + +/* + * protocol control block for the connection oriented network service + */ + +/* + * legit port #s for cons "transport" are 0..23 for su users only, and + * 1024..1099 for public users + */ +#define X25_SBSIZE 512 +#define X25_PORT_RESERVED 24 +#define X25_PORT_USERMAX 1099 +#define X25_FACIL_LEN_MAX 109 +#define X25_PARTIAL_PKT_LEN_MAX (MLEN - sizeof(struct cons_pcb)) + +#ifndef ARGO_DEBUG +#define X25_TTL 600 /* 5 min */ +#else /* ARGO_DEBUG */ +#define X25_TTL 120 /* 1 min */ +#endif /* ARGO_DEBUG */ + +struct cons_pcb { + struct isopcb _co_isopcb; +#define co_next _co_isopcb.isop_next +/* prev used for netstat only */ +#define co_prev _co_isopcb.isop_prev +#define co_head _co_isopcb.isop_head +#define co_laddr _co_isopcb.isop_laddr +#define co_faddr _co_isopcb.isop_faddr +#define co_lport _co_isopcb.isop_laddr.siso_tsuffix +#define co_fport _co_isopcb.isop_faddr.siso_tsuffix +#define co_route _co_isopcb.isop_route +#define co_socket _co_isopcb.isop_socket +#define co_chanmask _co_isopcb.isop_chanmask +#define co_negchanmask _co_isopcb.isop_negchanmask +#define co_x25crud _co_isopcb.isop_x25crud +#define co_x25crud_len _co_isopcb.isop_x25crud_len + u_short co_state; + u_char co_flags; + u_short co_ttl; /* time to live timer */ + u_short co_init_ttl; /* initial value of ttl */ + int co_channel; /* logical channel */ + struct ifnet * co_ifp; /* interface */ + struct protosw *co_proto; + + struct ifqueue co_pending; /* queue data to send when connection + completes*/ +#define MAX_DTE_LEN 0x7 /* 17 bcd digits */ + struct dte_addr co_peer_dte; + struct cons_pcb *co_myself; /* DEBUGGING AID */ +}; + +/* + * X.25 Packet types + */ +#define XPKT_DATA 1 +#define XPKT_INTERRUPT 2 +#define XPKT_FLOWCONTROL 3 /* not delivered? */ + +/* + * pcb xtates + */ + +#define CLOSED 0x0 +#define LISTENING 0x1 +#define CLOSING 0x2 +/* USABLE STATES MUST BE LAST */ +#define CONNECTING 0x3 +#define ACKWAIT 0x4 +#define OPEN 0x5 +#define MIN_USABLE_STATE CONNECTING + +#define cons_NSTATES 0x6 + + +/* type */ +#define CONSF_OCRE 0x40 /* created on OUTPUT */ +#define CONSF_ICRE 0x20 /* created on INPUT */ +#define CONSF_unused 0x10 /* not used */ +#define CONSF_unused2 0x08 /* not used */ +#define CONSF_DGM 0x04 /* for dgm use only */ +#define CONSF_XTS 0x02 /* for cons-as-transport-service */ +#define CONSF_LOOPBACK 0x01 /* loopback was on when connection commenced */ + +#define X_NOCHANNEL 0x80 + + +struct cons_stat { + u_int co_intr; /* input from eicon board */ + u_int co_restart; /* ecn_restart() request issued to board */ + u_int co_slowtimo; /* times slowtimo called */ + u_int co_timedout; /* connections closed by slowtimo */ + u_int co_ack; /* ECN_ACK indication came from eicon board */ + u_int co_receive; /* ECN_RECEIVE indication came from eicon board */ + u_int co_send; /* ECN_SEND request issued to board */ + u_int co_reset_in; /* ECN_RESET indication came from eicon board */ + u_int co_reset_out; /* ECN_RESET issued to the eicon board */ + u_int co_clear_in; /* ECN_CLEAR indication came from eicon board */ + u_int co_clear_out; /* ECN_CLEAR request issued to board */ + u_int co_refuse; /* ECN_REFUSE indication came from eicon board */ + u_int co_accept; /* ECN_ACCEPT indication came from eicon board */ + u_int co_connect; /* ECN_CONNECT indication came from eicon board */ + u_int co_call; /* ECN_CALL request issued to board */ + u_int co_Rdrops; /* bad pkt came from ll */ + u_int co_Xdrops; /* can't keep up */ + + u_int co_intrpt_pkts_in; /* interrupt packets in */ + u_int co_avg_qlen; + u_int co_avg_qdrop; + u_int co_active; + + u_int co_noresources; + u_int co_parse_facil_err; + u_int co_addr_proto_consist_err; + u_int co_no_copcb; +} cons_stat; + +u_char x25_error_stats[CONL_ERROR_MAX + 1]; + +struct ifqueue consintrq; + +/* reasons for clear are in a data mbuf chained to a clear ecn_request */ +struct e_clear_data { + u_char ecd_cause; + u_char ecd_diagnostic; +}; + +#ifdef KERNEL +#define IncStat(XYZ) cons_stat.XYZ++ +#endif /* KERNEL */ diff --git a/sys/netiso/eonvar.h b/sys/netiso/eonvar.h new file mode 100644 index 0000000..93f9917 --- /dev/null +++ b/sys/netiso/eonvar.h @@ -0,0 +1,170 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)eonvar.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#define EON_986_VERSION 0x3 +#define EON_VERSION 0x1 + +#define EON_CACHESIZE 30 + +#define E_FREE 1 +#define E_LINK 2 +#define E_ES 3 +#define E_IS 4 + + +/* + * this overlays a sockaddr_iso + */ + +struct sockaddr_eon { + u_char seon_len; /* Length */ + u_char seon_family; /* AF_ISO */ + u_char seon_status; /* overlays session suffixlen */ +#define EON_ESLINK_UP 0x1 +#define EON_ESLINK_DOWN 0x2 +#define EON_ISLINK_UP 0x10 +#define EON_ISLINK_DOWN 0x20 +/* no change is neither up or down */ + u_char seon_pad1; /* 0, overlays tsfxlen */ + u_char seon_adrlen; + u_char seon_afi; /* 47 */ + u_char seon_idi[2]; /* 0006 */ + u_char seon_vers; /* 03 */ + u_char seon_glbnum[2]; /* see RFC 1069 */ + u_char seon_RDN[2]; /* see RFC 1070 */ + u_char seon_pad2[3]; /* see RFC 1070 */ + u_char seon_LAREA[2]; /* see RFC 1070 */ + u_char seon_pad3[2]; /* see RFC 1070 */ + /* right now ip addr is aligned -- be careful -- + * future revisions may have it u_char[4] + */ + u_int seon_ipaddr; /* a.b.c.d */ + u_char seon_protoid; /* NSEL */ +}; + +#ifdef EON_TEMPLATE +struct sockaddr_eon eon_template = { + sizeof (eon_template), AF_ISO, 0, 0, 0x14, + 0x47, 0x0, 0x6, 0x3, 0 +}; +#endif + +#define DOWNBITS ( EON_ESLINK_DOWN | EON_ISLINK_DOWN ) +#define UPBITS ( EON_ESLINK_UP | EON_ISLINK_UP ) + +#define SIOCSEONCORE _IOWR('i',10, struct iso_ifreq) /* EON core member */ +#define SIOCGEONCORE _IOWR('i',11, struct iso_ifreq) /* EON core member */ + +struct eon_hdr { + u_char eonh_vers; /* value 1 */ + u_char eonh_class; /* address multicast class, below */ +#define EON_NORMAL_ADDR 0x0 +#define EON_MULTICAST_ES 0x1 +#define EON_MULTICAST_IS 0x2 +#define EON_BROADCAST 0x3 + u_short eonh_csum; /* osi checksum (choke)*/ +}; +struct eon_iphdr { + struct ip ei_ip; + struct eon_hdr ei_eh; +}; +#define EONIPLEN (sizeof(struct eon_hdr) + sizeof(struct ip)) + +/* stole these 2 fields of the flags for I-am-ES and I-am-IS */ +#define IFF_ES 0x400 +#define IFF_IS 0x800 + +struct eon_stat { + int es_in_multi_es; + int es_in_multi_is; + int es_in_broad; + int es_in_normal; + int es_out_multi_es; + int es_out_multi_is; + int es_out_broad; + int es_out_normal; + int es_ipout; + + int es_icmp[PRC_NCMDS]; + /* errors */ + int es_badcsum; + int es_badhdr; +} eonstat; + +#undef IncStat +#define IncStat(xxx) eonstat.xxx++ + +typedef struct qhdr { + struct qhdr *link, *rlink; +} *queue_t; + +struct eon_llinfo { + struct qhdr el_qhdr; /* keep all in a list */ + int el_flags; /* cache valid ? */ + int el_snpaoffset; /* IP address contained in dst nsap */ + struct rtentry *el_rt; /* back pointer to parent route */ + struct eon_iphdr el_ei; /* precomputed portion of hdr */ + struct route el_iproute; /* if direct route cache IP info */ + /* if gateway, cache secondary route */ +}; +#define el_iphdr el_ei.ei_ip +#define el_eonhdr el_ei.ei_eh diff --git a/sys/netiso/esis.c b/sys/netiso/esis.c new file mode 100644 index 0000000..f4ade0f --- /dev/null +++ b/sys/netiso/esis.c @@ -0,0 +1,1063 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)esis.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> +#include <net/raw_cb.h> + +#include <netiso/iso.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#include <netiso/clnl.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/esis.h> +#include <netiso/argo_debug.h> + +/* + * Global variables to esis implementation + * + * esis_holding_time - the holding time (sec) parameter for outgoing pdus + * esis_config_time - the frequency (sec) that hellos are generated + * esis_esconfig_time - suggested es configuration time placed in the + * ish. + * + */ +struct rawcb esis_pcb; +void esis_config(), snpac_age(); +int esis_sendspace = 2048; +int esis_recvspace = 2048; +short esis_holding_time = ESIS_HT; +short esis_config_time = ESIS_CONFIG; +short esis_esconfig_time = ESIS_CONFIG; +extern int iso_systype; +struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK }; +extern char all_es_snpa[], all_is_snpa[]; + +#define EXTEND_PACKET(m, mhdr, cp)\ + if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\ + esis_stat.es_nomem++;\ + m_freem(mhdr);\ + return;\ + } else {\ + (m) = (m)->m_next;\ + (cp) = mtod((m), caddr_t);\ + } +/* + * FUNCTION: esis_init + * + * PURPOSE: Initialize the kernel portion of esis protocol + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_init() +{ + extern struct clnl_protosw clnl_protox[256]; + int esis_input(), isis_input(); +#ifdef ISO_X25ESIS + int x25esis_input(); +#endif /* ISO_X25ESIS */ + + esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb; + llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc; + + timeout(snpac_age, (caddr_t)0, hz); + timeout(esis_config, (caddr_t)0, hz); + + clnl_protox[ISO9542_ESIS].clnl_input = esis_input; + clnl_protox[ISO10589_ISIS].clnl_input = isis_input; +#ifdef ISO_X25ESIS + clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input; +#endif /* ISO_X25ESIS */ +} + +/* + * FUNCTION: esis_usrreq + * + * PURPOSE: Handle user level esis requests + * + * RETURNS: 0 or appropriate errno + * + * SIDE EFFECTS: + * + */ +/*ARGSUSED*/ +esis_usrreq(so, req, m, nam, control) +struct socket *so; /* socket: used only to get to this code */ +int req; /* request */ +struct mbuf *m; /* data for request */ +struct mbuf *nam; /* optional name */ +struct mbuf *control; /* optional control */ +{ + struct rawcb *rp = sotorawcb(so); + int error = 0; + + if ((so->so_state & SS_PRIV) == 0) { + error = EACCES; + goto release; + } + if (rp == NULL && req != PRU_ATTACH) { + error = EINVAL; + goto release; + } + + switch (req) { + case PRU_ATTACH: + if (rp != NULL) { + error = EINVAL; + break; + } + MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK); + if (so->so_pcb = (caddr_t)rp) { + bzero(so->so_pcb, sizeof(*rp)); + insque(rp, &esis_pcb); + rp->rcb_socket = so; + error = soreserve(so, esis_sendspace, esis_recvspace); + } else + error = ENOBUFS; + break; + + case PRU_SEND: + if (nam == NULL) { + error = EINVAL; + break; + } + /* error checking here */ + error = isis_output(mtod(nam,struct sockaddr_dl *), m); + m = NULL; + break; + + case PRU_DETACH: + raw_detach(rp); + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_ABORT: + soisdisconnected(so); + raw_detach(rp); + break; + + case PRU_SENSE: + return (0); + + default: + return (EOPNOTSUPP); + } +release: + if (m != NULL) + m_freem(m); + + return (error); +} + +/* + * FUNCTION: esis_input + * + * PURPOSE: Process an incoming esis packet + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_input(m0, shp) +struct mbuf *m0; /* ptr to first mbuf of pkt */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + register struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); + register int type; + + /* + * check checksum if necessary + */ + if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) { + esis_stat.es_badcsum++; + goto bad; + } + + /* check version */ + if (pdu->esis_vers != ESIS_VERSION) { + esis_stat.es_badvers++; + goto bad; + } + type = pdu->esis_type & 0x1f; + switch (type) { + case ESIS_ESH: + esis_eshinput(m0, shp); + break; + + case ESIS_ISH: + esis_ishinput(m0, shp); + break; + + case ESIS_RD: + esis_rdinput(m0, shp); + break; + + default: + esis_stat.es_badtype++; + } + +bad: + if (esis_pcb.rcb_next != &esis_pcb) + isis_input(m0, shp); + else + m_freem(m0); +} + +/* + * FUNCTION: esis_rdoutput + * + * PURPOSE: Transmit a redirect pdu + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: Assumes there is enough space for fixed part of header, + * DA, BSNPA and NET in first mbuf. + */ +esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt) +struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ +struct mbuf *inbound_m; /* incoming pkt itself */ +struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ +struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ +struct rtentry *rt; /* snpa cache info regarding next hop of + pkt */ +{ + struct mbuf *m, *m0; + caddr_t cp; + struct esis_fixed *pdu; + int len, total_len = 0; + struct sockaddr_iso siso; + struct ifnet *ifp = inbound_shp->snh_ifp; + struct sockaddr_dl *sdl; + struct iso_addr *rd_gwnsap; + + if (rt->rt_flags & RTF_GATEWAY) { + rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr; + rt = rtalloc1(rt->rt_gateway, 0); + } else + rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr; + if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 || + sdl->sdl_family != AF_LINK) { + /* maybe we should have a function that you + could put in the iso_ifaddr structure + which could translate iso_addrs into snpa's + where there is a known mapping for that address type */ + esis_stat.es_badtype++; + return; + } + esis_stat.es_rdsent++; + IFDEBUG(D_ESISOUTPUT) + printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n", + ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m, + inbound_oidx); + printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap)); + printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap)); + ENDDEBUG + + if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { + esis_stat.es_nomem++; + return; + } + bzero(mtod(m, caddr_t), MHLEN); + + pdu = mtod(m, struct esis_fixed *); + cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */ + len = sizeof(struct esis_fixed); + + /* + * Build fixed part of header + */ + pdu->esis_proto_id = ISO9542_ESIS; + pdu->esis_vers = ESIS_VERSION; + pdu->esis_type = ESIS_RD; + HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time); + + /* Insert destination address */ + (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0); + + /* Insert the snpa of better next hop */ + *cp++ = sdl->sdl_alen; + bcopy(LLADDR(sdl), cp, sdl->sdl_alen); + cp += sdl->sdl_alen; + len += (sdl->sdl_alen + 1); + + /* + * If the next hop is not the destination, then it ought to be + * an IS and it should be inserted next. Else, set the + * NETL to 0 + */ + /* PHASE2 use mask from ifp of outgoing interface */ + if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) { + /* this should not happen: + if ((nhop_sc->sc_flags & SNPA_IS) == 0) { + printf("esis_rdoutput: next hop is not dst and not an IS\n"); + m_freem(m0); + return; + } */ + (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0); + } else { + *cp++ = 0; /* NETL */ + len++; + } + m->m_len = len; + + /* + * PHASE2 + * If redirect is to an IS, add an address mask. The mask to be + * used should be the mask present in the routing entry used to + * forward the original data packet. + */ + + /* + * Copy Qos, priority, or security options present in original npdu + */ + if (inbound_oidx) { + /* THIS CODE IS CURRENTLY (mostly) UNTESTED */ + int optlen = 0; + if (inbound_oidx->cni_qos_formatp) + optlen += (inbound_oidx->cni_qos_len + 2); + if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */ + optlen += 3; + if (inbound_oidx->cni_securep) + optlen += (inbound_oidx->cni_secure_len + 2); + if (M_TRAILINGSPACE(m) < optlen) { + EXTEND_PACKET(m, m0, cp); + m->m_len = 0; + /* assumes MLEN > optlen */ + } + /* assume MLEN-len > optlen */ + /* + * When copying options, copy from ptr - 2 in order to grab + * the option code and length + */ + if (inbound_oidx->cni_qos_formatp) { + bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2, + cp, (unsigned)(inbound_oidx->cni_qos_len + 2)); + cp += inbound_oidx->cni_qos_len + 2; + } + if (inbound_oidx->cni_priorp) { + bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2, + cp, 3); + cp += 3; + } + if (inbound_oidx->cni_securep) { + bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp, + (unsigned)(inbound_oidx->cni_secure_len + 2)); + cp += inbound_oidx->cni_secure_len + 2; + } + m->m_len += optlen; + len += optlen; + } + + pdu->esis_hdr_len = m0->m_pkthdr.len = len; + iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); + + bzero((caddr_t)&siso, sizeof(siso)); + siso.siso_family = AF_ISO; + siso.siso_data[0] = AFI_SNA; + siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */ + /* +1 is for AFI */ + bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6); + (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); +} + +/* + * FUNCTION: esis_insert_addr + * + * PURPOSE: Insert an iso_addr into a buffer + * + * RETURNS: true if buffer was big enough, else false + * + * SIDE EFFECTS: Increment buf & len according to size of iso_addr + * + * NOTES: Plus 1 here is for length byte + */ +esis_insert_addr(buf, len, isoa, m, nsellen) +register caddr_t *buf; /* ptr to buffer to put address into */ +int *len; /* ptr to length of buffer so far */ +register struct iso_addr *isoa; /* ptr to address */ +register struct mbuf *m; /* determine if there remains space */ +int nsellen; +{ + register int newlen, result = 0; + + isoa->isoa_len -= nsellen; + newlen = isoa->isoa_len + 1; + if (newlen <= M_TRAILINGSPACE(m)) { + bcopy((caddr_t)isoa, *buf, newlen); + *len += newlen; + *buf += newlen; + m->m_len += newlen; + result = 1; + } + isoa->isoa_len += nsellen; + return (result); +} + +#define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \ + if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} +#define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \ + if (b > buflim) {esis_stat.es_toosmall++; goto bad;}} +int ESHonly = 0; +/* + +/* + * FUNCTION: esis_eshinput + * + * PURPOSE: Process an incoming ESH pdu + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_eshinput(m, shp) +struct mbuf *m; /* esh pdu */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + struct esis_fixed *pdu = mtod(m, struct esis_fixed *); + u_short ht; /* holding time */ + struct iso_addr *nsap; + int naddr; + u_char *buf = (u_char *)(pdu + 1); + u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; + int new_entry = 0; + + esis_stat.es_eshrcvd++; + + CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); + + naddr = *buf++; + if (buf >= buflim) + goto bad; + if (naddr == 1) { + ESIS_EXTRACT_ADDR(nsap, buf); + new_entry = snpac_add(shp->snh_ifp, + nsap, shp->snh_shost, SNPA_ES, ht, 0); + } else { + int nsellength = 0, nlen = 0; + { + /* See if we want to compress out multiple nsaps differing + only by nsel */ + register struct ifaddr *ifa = shp->snh_ifp->if_addrlist; + for (; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_ISO) { + nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen; + break; + } + } + IFDEBUG(D_ESISINPUT) + printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n", + ht, naddr, nsellength); + ENDDEBUG + while (naddr-- > 0) { + struct iso_addr *nsap2; u_char *buf2; + ESIS_EXTRACT_ADDR(nsap, buf); + /* see if there is at least one more nsap in ESH differing + only by nsel */ + if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) { + ESIS_EXTRACT_ADDR(nsap2, buf2); + IFDEBUG(D_ESISINPUT) + printf("esis_eshinput: comparing %s ", + clnp_iso_addrp(nsap)); + printf("and %s\n", clnp_iso_addrp(nsap2)); + ENDDEBUG + if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr, + nsap->isoa_len - nsellength) == 0) { + nlen = nsellength; + break; + } + } + new_entry |= snpac_add(shp->snh_ifp, + nsap, shp->snh_shost, SNPA_ES, ht, nlen); + nlen = 0; + } + } + IFDEBUG(D_ESISINPUT) + printf("esis_eshinput: nsap %s is %s\n", + clnp_iso_addrp(nsap), new_entry ? "new" : "old"); + ENDDEBUG + if (new_entry && (iso_systype & SNPA_IS)) + esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time, + shp->snh_shost, 6, (struct iso_addr *)0); +bad: + return; +} + +/* + * FUNCTION: esis_ishinput + * + * PURPOSE: process an incoming ISH pdu + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_ishinput(m, shp) +struct mbuf *m; /* esh pdu */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + struct esis_fixed *pdu = mtod(m, struct esis_fixed *); + u_short ht, newct; /* holding time */ + struct iso_addr *nsap; /* Network Entity Title */ + register u_char *buf = (u_char *) (pdu + 1); + register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; + int new_entry; + + esis_stat.es_ishrcvd++; + CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); + + IFDEBUG(D_ESISINPUT) + printf("esis_ishinput: ish: ht %d\n", ht); + ENDDEBUG + if (ESHonly) + goto bad; + + ESIS_EXTRACT_ADDR(nsap, buf); + + while (buf < buflim) { + switch (*buf) { + case ESISOVAL_ESCT: + if (iso_systype & SNPA_IS) + break; + if (buf[1] != 2) + goto bad; + CTOH(buf[2], buf[3], newct); + if (esis_config_time != newct) { + untimeout(esis_config,0); + esis_config_time = newct; + esis_config(); + } + break; + + default: + printf("Unknown ISH option: %x\n", *buf); + } + ESIS_NEXT_OPTION(buf); + } + new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0); + IFDEBUG(D_ESISINPUT) + printf("esis_ishinput: nsap %s is %s\n", + clnp_iso_addrp(nsap), new_entry ? "new" : "old"); + ENDDEBUG + + if (new_entry) + esis_shoutput(shp->snh_ifp, + iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, + esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0); +bad: + return; +} + +/* + * FUNCTION: esis_rdinput + * + * PURPOSE: Process an incoming RD pdu + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_rdinput(m0, shp) +struct mbuf *m0; /* esh pdu */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + struct esis_fixed *pdu = mtod(m0, struct esis_fixed *); + u_short ht; /* holding time */ + struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0; + register struct iso_addr *bsnpa; + register u_char *buf = (u_char *)(pdu + 1); + register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu; + + esis_stat.es_rdrcvd++; + + /* intermediate systems ignore redirects */ + if (iso_systype & SNPA_IS) + return; + if (ESHonly) + return; + + CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); + if (buf >= buflim) + return; + + /* Extract DA */ + ESIS_EXTRACT_ADDR(da, buf); + + /* Extract better snpa */ + ESIS_EXTRACT_ADDR(bsnpa, buf); + + /* Extract NET if present */ + if (buf < buflim) { + if (*buf == 0) + buf++; /* no NET present, skip NETL anyway */ + else + ESIS_EXTRACT_ADDR(net, buf); + } + + /* process options */ + while (buf < buflim) { + switch (*buf) { + case ESISOVAL_SNPAMASK: + if (snpamask) /* duplicate */ + return; + snpamask = (struct iso_addr *)(buf + 1); + break; + + case ESISOVAL_NETMASK: + if (netmask) /* duplicate */ + return; + netmask = (struct iso_addr *)(buf + 1); + break; + + default: + printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]); + } + ESIS_NEXT_OPTION(buf); + } + + IFDEBUG(D_ESISINPUT) + printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da)); + if (net) + printf("\t: net %s\n", clnp_iso_addrp(net)); + ENDDEBUG + /* + * If netl is zero, then redirect is to an ES. We need to add an entry + * to the snpa cache for (destination, better snpa). + * If netl is not zero, then the redirect is to an IS. In this + * case, add an snpa cache entry for (net, better snpa). + * + * If the redirect is to an IS, add a route entry towards that + * IS. + */ + if (net == 0 || net->isoa_len == 0 || snpamask) { + /* redirect to an ES */ + snpac_add(shp->snh_ifp, da, + bsnpa->isoa_genaddr, SNPA_ES, ht, 0); + } else { + snpac_add(shp->snh_ifp, net, + bsnpa->isoa_genaddr, SNPA_IS, ht, 0); + snpac_addrt(shp->snh_ifp, da, net, netmask); + } +bad: ; /* Needed by ESIS_NEXT_OPTION */ +} + +/* + * FUNCTION: esis_config + * + * PURPOSE: Report configuration + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: Called every esis_config_time seconds + */ +void +esis_config() +{ + register struct ifnet *ifp; + + timeout(esis_config, (caddr_t)0, hz * esis_config_time); + + /* + * Report configuration for each interface that + * - is UP + * - has BROADCAST capability + * - has an ISO address + */ + /* Todo: a better way would be to construct the esh or ish + * once and copy it out for all devices, possibly calling + * a method in the iso_ifaddr structure to encapsulate and + * transmit it. This could work to advantage for non-broadcast media + */ + + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + if ((ifp->if_flags & IFF_UP) && + (ifp->if_flags & IFF_BROADCAST)) { + /* search for an ISO address family */ + struct ifaddr *ia; + + for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) { + if (ia->ifa_addr->sa_family == AF_ISO) { + esis_shoutput(ifp, + iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH, + esis_holding_time, + (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa : + all_es_snpa), 6, (struct iso_addr *)0); + break; + } + } + } + } +} + +/* + * FUNCTION: esis_shoutput + * + * PURPOSE: Transmit an esh or ish pdu + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa) +struct ifnet *ifp; +int type; +short ht; +caddr_t sn_addr; +int sn_len; +struct iso_addr *isoa; +{ + struct mbuf *m, *m0; + caddr_t cp, naddrp; + int naddr = 0; + struct esis_fixed *pdu; + struct iso_ifaddr *ia; + int len; + struct sockaddr_iso siso; + + if (type == ESIS_ESH) + esis_stat.es_eshsent++; + else if (type == ESIS_ISH) + esis_stat.es_ishsent++; + else { + printf("esis_shoutput: bad pdu type\n"); + return; + } + + IFDEBUG(D_ESISOUTPUT) + int i; + printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ", + ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish", + ht, sn_len); + for (i=0; i<sn_len; i++) + printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' '); + printf("\n"); + ENDDEBUG + + if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) { + esis_stat.es_nomem++; + return; + } + bzero(mtod(m, caddr_t), MHLEN); + + pdu = mtod(m, struct esis_fixed *); + naddrp = cp = (caddr_t)(pdu + 1); + len = sizeof(struct esis_fixed); + + /* + * Build fixed part of header + */ + pdu->esis_proto_id = ISO9542_ESIS; + pdu->esis_vers = ESIS_VERSION; + pdu->esis_type = type; + HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht); + + if (type == ESIS_ESH) { + cp++; + len++; + } + + m->m_len = len; + if (isoa) { + /* + * Here we are responding to a clnp packet sent to an NSAP + * that is ours which was sent to the MAC addr all_es's. + * It is possible that we did not specifically advertise this + * NSAP, even though it is ours, so we will respond + * directly to the sender that we are here. If we do have + * multiple NSEL's we'll tack them on so he can compress them out. + */ + (void) esis_insert_addr(&cp, &len, isoa, m, 0); + naddr = 1; + } + for (ia = iso_ifaddr; ia; ia = ia->ia_next) { + int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0); + int n = ia->ia_addr.siso_nlen; + register struct iso_ifaddr *ia2; + + if (type == ESIS_ISH && naddr > 0) + break; + for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next) + if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0) + break; + if (ia2 != ia) + continue; /* Means we have previously copied this nsap */ + if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) { + isoa = 0; + continue; /* Ditto */ + } + IFDEBUG(D_ESISOUTPUT) + printf("esis_shoutput: adding NSAP %s\n", + clnp_iso_addrp(&ia->ia_addr.siso_addr)); + ENDDEBUG + if (!esis_insert_addr(&cp, &len, + &ia->ia_addr.siso_addr, m, nsellen)) { + EXTEND_PACKET(m, m0, cp); + (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m, + nsellen); + } + naddr++; + } + + if (type == ESIS_ESH) + *naddrp = naddr; + else { + /* add suggested es config timer option to ISH */ + if (M_TRAILINGSPACE(m) < 4) { + printf("esis_shoutput: extending packet\n"); + EXTEND_PACKET(m, m0, cp); + } + *cp++ = ESISOVAL_ESCT; + *cp++ = 2; + HTOC(*cp, *(cp+1), esis_esconfig_time); + len += 4; + m->m_len += 4; + IFDEBUG(D_ESISOUTPUT) + printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n", + m0, m, m->m_data, m->m_len, cp); + ENDDEBUG + } + + m0->m_pkthdr.len = len; + pdu->esis_hdr_len = len; + iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len); + + bzero((caddr_t)&siso, sizeof(siso)); + siso.siso_family = AF_ISO; + siso.siso_data[0] = AFI_SNA; + siso.siso_nlen = sn_len + 1; + bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len); + (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0); +} + +/* + * FUNCTION: isis_input + * + * PURPOSE: Process an incoming isis packet + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +isis_input(m0, shp) +struct mbuf *m0; /* ptr to first mbuf of pkt */ +struct snpa_hdr *shp; /* subnetwork header */ +{ + register int type; + register struct rawcb *rp, *first_rp = 0; + struct ifnet *ifp = shp->snh_ifp; + char workbuf[16]; + struct mbuf *mm; + + IFDEBUG(D_ISISINPUT) + int i; + + printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp, + ifp->if_name, ifp->if_unit); + for (i=0; i<6; i++) + printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' '); + printf(" to:"); + for (i=0; i<6; i++) + printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' '); + printf("\n"); + ENDDEBUG + esis_dl.sdl_alen = ifp->if_addrlen; + esis_dl.sdl_index = ifp->if_index; + bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen); + for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) { + if (first_rp == 0) { + first_rp = rp; + continue; + } + if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */ + if (sbappendaddr(&rp->rcb_socket->so_rcv, + &esis_dl, mm, (struct mbuf *)0) != 0) { + sorwakeup(rp->rcb_socket); + } else { + IFDEBUG(D_ISISINPUT) + printf("Error in sbappenaddr, mm = 0x%x\n", mm); + ENDDEBUG + m_freem(mm); + } + } + } + if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv, + &esis_dl, m0, (struct mbuf *)0) != 0) { + sorwakeup(first_rp->rcb_socket); + return; + } + m_freem(m0); +} + +isis_output(sdl, m) +register struct sockaddr_dl *sdl; +struct mbuf *m; +{ + register struct ifnet *ifp; + struct ifaddr *ifa, *ifa_ifwithnet(); + struct sockaddr_iso siso; + int error = 0; + unsigned sn_len; + + ifa = ifa_ifwithnet((struct sockaddr *)sdl); /* get ifp from sdl */ + if (ifa == 0) { + IFDEBUG(D_ISISOUTPUT) + printf("isis_output: interface not found\n"); + ENDDEBUG + error = EINVAL; + goto release; + } + ifp = ifa->ifa_ifp; + sn_len = sdl->sdl_alen; + IFDEBUG(D_ISISOUTPUT) + u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len; + printf("isis_output: ifp 0x%x (%s%d), to: ", + ifp, ifp->if_name, ifp->if_unit); + while (cp < cplim) { + printf("%x", *cp++); + printf("%c", (cp < cplim) ? ':' : ' '); + } + printf("\n"); + ENDDEBUG + bzero((caddr_t)&siso, sizeof(siso)); + siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */ + siso.siso_data[0] = AFI_SNA; + siso.siso_nlen = sn_len + 1; + bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len); + error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0); + if (error) { + IFDEBUG(D_ISISOUTPUT) + printf("isis_output: error from ether_output is %d\n", error); + ENDDEBUG + } + return (error); + +release: + if (m != NULL) + m_freem(m); + return(error); +} + + +/* + * FUNCTION: esis_ctlinput + * + * PURPOSE: Handle the PRC_IFDOWN transition + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: Calls snpac_flush for interface specified. + * The loop through iso_ifaddr is stupid because + * back in if_down, we knew the ifp... + */ +esis_ctlinput(req, siso) +int req; /* request: we handle only PRC_IFDOWN */ +struct sockaddr_iso *siso; /* address of ifp */ +{ + register struct iso_ifaddr *ia; /* scan through interface addresses */ + + if (req == PRC_IFDOWN) + for (ia = iso_ifaddr; ia; ia = ia->ia_next) { + if (iso_addrmatch(IA_SIS(ia), siso)) + snpac_flushifp(ia->ia_ifp); + } +} + +#endif /* ISO */ diff --git a/sys/netiso/esis.h b/sys/netiso/esis.h new file mode 100644 index 0000000..81dd74a --- /dev/null +++ b/sys/netiso/esis.h @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)esis.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: esis.h,v 4.7 88/09/15 11:24:18 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/esis.h,v $ + */ + +#ifndef BYTE_ORDER +/* + * Definitions for byte order, + * according to byte significance from low address to high. + */ +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ + +#ifdef vax +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */ +#endif +#endif /* BYTE_ORDER */ + +#define SNPAC_AGE 60 /* seconds */ +#define ESIS_CONFIG 60 /* seconds */ +#define ESIS_HT (ESIS_CONFIG * 2) + +/* + * Fixed part of an ESIS header + */ +struct esis_fixed { + u_char esis_proto_id; /* network layer protocol identifier */ + u_char esis_hdr_len; /* length indicator (octets) */ + u_char esis_vers; /* version/protocol identifier extension */ + u_char esis_res1; /* reserved */ + u_char esis_type; /* type code */ +/* technically, type should be &='d 0x1f */ +#define ESIS_ESH 0x02 /* End System Hello */ +#define ESIS_ISH 0x04 /* Intermediate System Hello */ +#define ESIS_RD 0x06 /* Redirect */ + u_char esis_ht_msb; /* holding time (seconds) high byte */ + u_char esis_ht_lsb; /* holding time (seconds) low byte */ + u_char esis_cksum_msb; /* checksum high byte */ + u_char esis_cksum_lsb; /* checksum low byte */ +}; +/* + * Values for ESIS datagram options + */ +#define ESISOVAL_NETMASK 0xe1 /* address mask option, RD PDU only */ +#define ESISOVAL_SNPAMASK 0xe2 /* snpa mask option, RD PDU only */ +#define ESISOVAL_ESCT 0xc6 /* end system conf. timer, ISH PDU only */ + + +#define ESIS_CKSUM_OFF 0x07 +#define ESIS_CKSUM_REQUIRED(pdu)\ + ((pdu->esis_cksum_msb != 0) || (pdu->esis_cksum_lsb != 0)) + +#define ESIS_VERSION 1 + +struct esis_stat { + u_short es_nomem; /* insufficient memory to send hello */ + u_short es_badcsum; /* incorrect checksum */ + u_short es_badvers; /* incorrect version number */ + u_short es_badtype; /* unknown pdu type field */ + u_short es_toosmall; /* packet too small */ + u_short es_eshsent; /* ESH sent */ + u_short es_eshrcvd; /* ESH rcvd */ + u_short es_ishsent; /* ISH sent */ + u_short es_ishrcvd; /* ISH rcvd */ + u_short es_rdsent; /* RD sent */ + u_short es_rdrcvd; /* RD rcvd */ +}; + +#ifdef KERNEL +struct esis_stat esis_stat; +#endif /* KERNEL */ diff --git a/sys/netiso/idrp_usrreq.c b/sys/netiso/idrp_usrreq.c new file mode 100644 index 0000000..3109936 --- /dev/null +++ b/sys/netiso/idrp_usrreq.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)idrp_usrreq.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/route.h> +#include <net/if.h> + +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/clnl.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> + +int idrp_input(); +struct isopcb idrp_isop; +static struct sockaddr_iso idrp_addrs[2] = +{ { sizeof(idrp_addrs), AF_ISO, }, { sizeof(idrp_addrs[1]), AF_ISO, } }; +/* + * IDRP initialization + */ +idrp_init() +{ + extern struct clnl_protosw clnl_protox[256]; + + idrp_isop.isop_next = idrp_isop.isop_prev = &idrp_isop; + idrp_isop.isop_faddr = &idrp_isop.isop_sfaddr; + idrp_isop.isop_laddr = &idrp_isop.isop_sladdr; + idrp_isop.isop_sladdr = idrp_addrs[1]; + idrp_isop.isop_sfaddr = idrp_addrs[1]; + clnl_protox[ISO10747_IDRP].clnl_input = idrp_input; +} + +/* + * CALLED FROM: + * tpclnp_input(). + * FUNCTION and ARGUMENTS: + * Take a packet (m) from clnp, strip off the clnp header + * and mke suitable for the idrp socket. + * No return value. + */ +idrp_input(m, src, dst) + register struct mbuf *m; + struct sockaddr_iso *src, *dst; +{ + if (idrp_isop.isop_socket == 0) { + bad: m_freem(m); + return 0; + } + bzero(idrp_addrs[0].siso_data, sizeof(idrp_addrs[0].siso_data)); + bcopy((caddr_t)&(src->siso_addr), (caddr_t)&idrp_addrs[0].siso_addr, + 1 + src->siso_nlen); + bzero(idrp_addrs[1].siso_data, sizeof(idrp_addrs[1].siso_data)); + bcopy((caddr_t)&(dst->siso_addr), (caddr_t)&idrp_addrs[1].siso_addr, + 1 + dst->siso_nlen); + if (sbappendaddr(&idrp_isop.isop_socket->so_rcv, + (struct sockaddr *)idrp_addrs, m, (struct mbuf *)0) == 0) + goto bad; + sorwakeup(idrp_isop.isop_socket); + return 0; +} + +idrp_output(m, addr) + struct mbuf *m, *addr; +{ + register struct sockaddr_iso *siso = mtod(addr, struct sockaddr_iso *); + int s = splnet(), i; + + bcopy((caddr_t)&(siso->siso_addr), + (caddr_t)&idrp_isop.isop_sfaddr.siso_addr, 1 + siso->siso_nlen); + siso++; + bcopy((caddr_t)&(siso->siso_addr), + (caddr_t)&idrp_isop.isop_sladdr.siso_addr, 1 + siso->siso_nlen); + i = clnp_output(m, idrp_isop, m->m_pkthdr.len, 0); + splx(s); + return (i); +} + +u_long idrp_sendspace = 3072; /* really max datagram size */ +u_long idrp_recvspace = 40 * 1024; /* 40 1K datagrams */ + +/*ARGSUSED*/ +idrp_usrreq(so, req, m, addr, control) + struct socket *so; + int req; + struct mbuf *m, *addr, *control; +{ + int error = 0; + + /* Note: need to block idrp_input while changing + * the udp pcb queue and/or pcb addresses. + */ + switch (req) { + + case PRU_ATTACH: + if (idrp_isop.isop_socket != NULL) { + error = ENXIO; + break; + } + idrp_isop.isop_socket = so; + error = soreserve(so, idrp_sendspace, idrp_recvspace); + break; + + case PRU_SHUTDOWN: + socantsendmore(so); + break; + + case PRU_SEND: + return (idrp_output(m, addr)); + + case PRU_ABORT: + soisdisconnected(so); + case PRU_DETACH: + idrp_isop.isop_socket = 0; + break; + + + case PRU_SENSE: + /* + * stat: don't bother with a blocksize. + */ + return (0); + + default: + return (EOPNOTSUPP); /* do not free mbuf's */ + } + +release: + if (control) { + printf("idrp control data unexpectedly retained\n"); + m_freem(control); + } + if (m) + m_freem(m); + return (error); +} diff --git a/sys/netiso/if_cons.c b/sys/netiso/if_cons.c new file mode 100644 index 0000000..7724b04 --- /dev/null +++ b/sys/netiso/if_cons.c @@ -0,0 +1,960 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_cons.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: if_cons.c,v 4.7 88/08/11 15:52:55 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/if_cons.c,v $ + * + * cons.c - Connection Oriented Network Service: + * including support for a) user transport-level service, + * b) COSNS below CLNP, and c) CONS below TP. + */ + +#ifdef TPCONS +#ifdef KERNEL +#ifdef ARGO_DEBUG +#define Static +unsigned LAST_CALL_PCB; +#else /* ARGO_DEBUG */ +#define Static static +#endif /* ARGO_DEBUG */ + +#ifndef SOCK_STREAM +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/tsleep.h> + +#include <net/if.h> +#include <net/netisr.h> +#include <net/route.h> + +#include <netiso/iso_errno.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> +#include <netiso/iso.h> +#include <netiso/cons.h> +#include <netiso/iso_pcb.h> + +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> +#endif + +#ifdef ARGO_DEBUG +#define MT_XCONN 0x50 +#define MT_XCLOSE 0x51 +#define MT_XCONFIRM 0x52 +#define MT_XDATA 0x53 +#define MT_XHEADER 0x54 +#else +#define MT_XCONN MT_DATA +#define MT_XCLOSE MT_DATA +#define MT_XCONFIRM MT_DATA +#define MT_XDATA MT_DATA +#define MT_XHEADER MT_HEADER +#endif /* ARGO_DEBUG */ + +#define DONTCLEAR -1 + +/********************************************************************* + * cons.c - CONS interface to the x.25 layer + * + * TODO: figure out what resources we might run out of besides mbufs. + * If we run out of any of them (including mbufs) close and recycle + * lru x% of the connections, for some parameter x. + * + * There are 2 interfaces from above: + * 1) from TP0: + * cons CO network service + * TP associates a transport connection with a network connection. + * cons_output( isop, m, len, isdgm==0 ) + * co_flags == 0 + * 2) from TP4: + * It's a datagram service, like clnp is. - even though it calls + * cons_output( isop, m, len, isdgm==1 ) + * it eventually goes through + * cosns_output(ifp, m, dst). + * TP4 permits multiplexing (reuse, possibly simultaneously) of the + * network connections. + * This means that many sockets (many tpcbs) may be associated with + * this pklcd, hence cannot have a back ptr from pklcd to a tpcb. + * co_flags & CONSF_DGM + * co_socket is null since there may be many sockets that use this pklcd. + * +NOTE: + streams would really be nice. sigh. +NOTE: + PVCs could be handled by config-ing a cons with an address and with the + IFF_POINTTOPOINT flag on. This code would then have to skip the + connection setup stuff for pt-to-pt links. + + + *********************************************************************/ + + +#define CONS_IFQMAXLEN 5 + + +/* protosw pointers for getting to higher layer */ +Static struct protosw *CLNP_proto; +Static struct protosw *TP_proto; +Static struct protosw *X25_proto; +Static int issue_clear_req(); + +#ifndef PHASEONE +extern struct ifaddr *ifa_ifwithnet(); +#endif /* PHASEONE */ + +extern struct ifaddr *ifa_ifwithaddr(); + +extern struct isopcb tp_isopcb; /* chain of all TP pcbs */ + + +Static int parse_facil(), NSAPtoDTE(), make_partial_x25_packet(); +Static int FACILtoNSAP(), DTEtoNSAP(); +Static struct pklcd *cons_chan_to_pcb(); + +#define HIGH_NIBBLE 1 +#define LOW_NIBBLE 0 + +/* + * NAME: nibble_copy() + * FUNCTION and ARGUMENTS: + * copies (len) nibbles from (src_octet), high or low nibble + * to (dst_octet), high or low nibble, + * src_nibble & dst_nibble should be: + * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble + * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble + * RETURNS: VOID + */ +void +nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len) + register char *src_octet; + register char *dst_octet; + register unsigned src_nibble; + register unsigned dst_nibble; + int len; +{ + + register i; + register unsigned dshift, sshift; + + IFDEBUG(D_CADDR) + printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", + src_octet, src_nibble, dst_octet, dst_nibble, len); + ENDDEBUG +#define SHIFT 0x4 + + dshift = dst_nibble << 2; + sshift = src_nibble << 2; + + for (i=0; i<len; i++) { + /* clear dst_nibble */ + *dst_octet &= ~(0xf<< dshift); + + /* set dst nibble */ + *dst_octet |= ( 0xf & (*src_octet >> sshift))<< dshift; + + dshift ^= SHIFT; + sshift ^= SHIFT; + src_nibble = 1-src_nibble; + dst_nibble = 1-dst_nibble; + src_octet += src_nibble; + dst_octet += dst_nibble; + } + IFDEBUG(D_CADDR) + printf("nibble_copy DONE\n"); + ENDDEBUG +} + +/* + * NAME: nibble_match() + * FUNCTION and ARGUMENTS: + * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles. + * RETURNS: 0 if they differ, 1 if they are the same. + */ +int +nibble_match( src_octet, src_nibble, dst_octet, dst_nibble, len) + register char *src_octet; + register char *dst_octet; + register unsigned src_nibble; + register unsigned dst_nibble; + int len; +{ + + register i; + register unsigned dshift, sshift; + u_char nibble_a, nibble_b; + + IFDEBUG(D_CADDR) + printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n", + src_octet, src_nibble, dst_octet, dst_nibble, len); + ENDDEBUG +#define SHIFT 0x4 + + dshift = dst_nibble << 2; + sshift = src_nibble << 2; + + for (i=0; i<len; i++) { + nibble_b = ((*dst_octet)>>dshift) & 0xf; + nibble_a = ( 0xf & (*src_octet >> sshift)); + if (nibble_b != nibble_a) + return 0; + + dshift ^= SHIFT; + sshift ^= SHIFT; + src_nibble = 1-src_nibble; + dst_nibble = 1-dst_nibble; + src_octet += src_nibble; + dst_octet += dst_nibble; + } + IFDEBUG(D_CADDR) + printf("nibble_match DONE\n"); + ENDDEBUG + return 1; +} + +/* + **************************** NET PROTOCOL cons *************************** + */ +/* + * NAME: cons_init() + * CALLED FROM: + * autoconf + * FUNCTION: + * initialize the protocol + */ +cons_init() +{ + int tp_incoming(), clnp_incoming(); + + + CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM); + X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM); + TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET); + IFDEBUG(D_CCONS) + printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n", + CLNP_proto, X25_proto, TP_proto); + ENDDEBUG +#ifdef notdef + pk_protolisten(0x81, 0, clnp_incoming); + pk_protolisten(0x82, 0, esis_incoming); + pk_protolisten(0x84, 0, tp8878_A_incoming); + pk_protolisten(0, 0, tp_incoming); +#endif +} + +tp_incoming(lcp, m) +struct pklcd *lcp; +register struct mbuf *m; +{ + register struct isopcb *isop; + int cons_tpinput(); + + if (iso_pcballoc((struct socket *)0, &tp_isopcb)) { + pk_close(lcp); + return; + } + isop = tp_isopcb.isop_next; + lcp->lcd_upper = cons_tpinput; + lcp->lcd_upnext = (caddr_t)isop; + lcp->lcd_send(lcp); /* Confirms call */ + isop->isop_chan = (caddr_t)lcp; + isop->isop_laddr = &isop->isop_sladdr; + isop->isop_faddr = &isop->isop_sfaddr; + DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr); + DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr); + parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data), + m->m_pkthdr.len - PKHEADERLN); +} + +cons_tpinput(lcp, m0) +struct mbuf *m0; +struct pklcd *lcp; +{ + register struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; + register struct x25_packet *xp; + int cmd, ptype = CLEAR; + + if (isop == 0) + return; + if (m0 == 0) + goto dead; + switch(m0->m_type) { + case MT_DATA: + case MT_OOBDATA: + tpcons_input(m0, isop->isop_faddr, isop->isop_laddr, (caddr_t)lcp); + return; + + case MT_CONTROL: + switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) { + + case RR: + cmd = PRC_CONS_SEND_DONE; + break; + + case CALL_ACCEPTED: + if (lcp->lcd_sb.sb_mb) + lcp->lcd_send(lcp); /* XXX - fix this */ + /*FALLTHROUGH*/ + default: + return; + + dead: + case CLEAR: + case CLEAR_CONF: + lcp->lcd_upper = 0; + lcp->lcd_upnext = 0; + isop->isop_chan = 0; + case RESET: + cmd = PRC_ROUTEDEAD; + } + tpcons_ctlinput(cmd, isop->isop_faddr, isop); + if (cmd = PRC_ROUTEDEAD && isop->isop_refcnt == 0) + iso_pcbdetach(isop); + } +} + +/* + * NAME: cons_connect() + * CALLED FROM: + * tpcons_pcbconnect() when opening a new connection. + * FUNCTION anD ARGUMENTS: + * Figures out which device to use, finding a route if one doesn't + * already exist. + * RETURN VALUE: + * returns E* + */ +cons_connect(isop) + register struct isopcb *isop; +{ + register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; + register struct mbuf *m; + struct ifaddr *ifa; + int error; + + IFDEBUG(D_CCONN) + printf("cons_connect(0x%x): ", isop); + dump_isoaddr(isop->isop_faddr); + printf("myaddr: "); + dump_isoaddr(isop->isop_laddr); + printf("\n" ); + ENDDEBUG + NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr); + lcp->lcd_upper = cons_tpinput; + lcp->lcd_upnext = (caddr_t)isop; + IFDEBUG(D_CCONN) + printf( + "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n", + &lcp->lcd_faddr, &lcp->lcd_laddr, + isop->isop_socket->so_proto->pr_protocol); + ENDDEBUG + if ((error = make_partial_x25_packet(isop, lcp, m)) == 0) + error = pk_connect(lcp, &lcp->lcd_faddr); + return error; +} + +/* + **************************** DEVICE cons *************************** + */ + + +/* + * NAME: cons_ctlinput() + * CALLED FROM: + * lower layer when ECN_CLEAR occurs : this routine is here + * for consistency - cons subnet service calls its higher layer + * through the protosw entry. + * FUNCTION & ARGUMENTS: + * cmd is a PRC_* command, list found in ../sys/protosw.h + * copcb is the obvious. + * This serves the higher-layer cons service. + * NOTE: this takes 3rd arg. because cons uses it to inform itself + * of things (timeouts, etc) but has a pcb instead of an address. + */ +cons_ctlinput(cmd, sa, copcb) + int cmd; + struct sockaddr *sa; + register struct pklcd *copcb; +{ +} + + +find_error_reason( xp ) + register struct x25_packet *xp; +{ + extern u_char x25_error_stats[]; + int error, cause; + + if (xp) { + cause = 4[(char *)xp]; + switch (cause) { + case 0x00: + case 0x80: + /* DTE originated; look at the diagnostic */ + error = (CONL_ERROR_MASK | cause); + goto done; + + case 0x01: /* number busy */ + case 0x81: + case 0x09: /* Out of order */ + case 0x89: + case 0x11: /* Remot Procedure Error */ + case 0x91: + case 0x19: /* reverse charging accept not subscribed */ + case 0x99: + case 0x21: /* Incampat destination */ + case 0xa1: + case 0x29: /* fast select accept not subscribed */ + case 0xa9: + case 0x39: /* ship absent */ + case 0xb9: + case 0x03: /* invalid facil request */ + case 0x83: + case 0x0b: /* access barred */ + case 0x8b: + case 0x13: /* local procedure error */ + case 0x93: + case 0x05: /* network congestion */ + case 0x85: + case 0x8d: /* not obtainable */ + case 0x0d: + case 0x95: /* RPOA out of order */ + case 0x15: + /* take out bit 8 + * so we don't have to have so many perror entries + */ + error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80)); + goto done; + + case 0xc1: /* gateway-detected proc error */ + case 0xc3: /* gateway congestion */ + + error = (CONL_ERROR_MASK | 0x100 | cause); + goto done; + } + } + /* otherwise, a *hopefully* valid perror exists in the e_reason field */ + error = xp->packet_data; + if (error = 0) { + printf("Incoming PKT TYPE 0x%x with reason 0x%x\n", + pk_decode(xp), + cause); + error = E_CO_HLI_DISCA; + } + +done: + return error; +} + + + +#endif /* KERNEL */ + +/* + * NAME: make_partial_x25_packet() + * + * FUNCTION and ARGUMENTS: + * Makes part of an X.25 call packet, for use by x25. + * (src) and (dst) are the NSAP-addresses of source and destination. + * (buf) is a ptr to a buffer into which to write this partial header. + * + * 0 Facility length (in octets) + * 1 Facility field, which is a set of: + * m facil code + * m+1 facil param len (for >2-byte facilities) in octets + * m+2..p facil param field + * q user data (protocol identification octet) + * + * + * RETURNS: + * 0 if OK + * E* if failed. + * + * SIDE EFFECTS: + * Stores facilites mbuf in X.25 control block, where the connect + * routine knows where to look for it. + */ + +#ifdef X25_1984 +int cons_use_facils = 1; +#else /* X25_1984 */ +int cons_use_facils = 0; +#endif /* X25_1984 */ + +int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */ + +Static int +make_partial_x25_packet(isop, lcp) + struct isopcb *isop; + struct pklcd *lcp; +{ + u_int proto; + int flag; + caddr_t buf; + register caddr_t ptr; + register int len = 0; + int buflen =0; + caddr_t facil_len; + int oddness = 0; + struct mbuf *m; + + + IFDEBUG(D_CCONN) + printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n", + isop->isop_laddr, isop->isop_faddr, proto, m, flag); + ENDDEBUG + if (cons_use_udata) { + if (isop->isop_x25crud_len > 0) { + /* + * The user specified something. Stick it in + */ + bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata, + isop->isop_x25crud_len); + lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len; + } + } + + if (cons_use_facils == 0) { + lcp->lcd_facilities = 0; + return 0; + } + MGETHDR(m, MT_DATA, M_WAITOK); + if (m == 0) + return ENOBUFS; + buf = mtod(m, caddr_t); + ptr = buf; + + /* ptr now points to facil length (len of whole facil field in OCTETS */ + facil_len = ptr ++; + m->m_len = 0; + pk_build_facilities(m, &lcp->lcd_faddr, 0); + + IFDEBUG(D_CADDR) + printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr, + isop->isop_laddr->siso_addr.isoa_len); + ENDDEBUG + if (cons_use_facils) { + *ptr++ = 0; /* Marker to separate X.25 facitilies from CCITT ones */ + *ptr++ = 0x0f; + *ptr = 0xcb; /* calling facility code */ + ptr ++; + ptr ++; /* leave room for facil param len (in OCTETS + 1) */ + ptr ++; /* leave room for the facil param len (in nibbles), + * high two bits of which indicate full/partial NSAP + */ + len = isop->isop_laddr->siso_addr.isoa_len; + bcopy( isop->isop_laddr->siso_data, ptr, len); + *(ptr-2) = len+1; /* facil param len in octets */ + *(ptr-1) = len<<1; /* facil param len in nibbles */ + ptr += len; + + IFDEBUG(D_CADDR) + printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr, + isop->isop_faddr->siso_addr.isoa_len); + ENDDEBUG + *ptr = 0xc9; /* called facility code */ + ptr ++; + ptr ++; /* leave room for facil param len (in OCTETS + 1) */ + ptr ++; /* leave room for the facil param len (in nibbles), + * high two bits of which indicate full/partial NSAP + */ + len = isop->isop_faddr->siso_nlen; + bcopy(isop->isop_faddr->siso_data, ptr, len); + *(ptr-2) = len+1; /* facil param len = addr len + 1 for each of these + * two length fields, in octets */ + *(ptr-1) = len<<1; /* facil param len in nibbles */ + ptr += len; + + } + *facil_len = ptr - facil_len - 1; + if (*facil_len > MAX_FACILITIES) + return E_CO_PNA_LONG; + + buflen = (int)(ptr - buf); + + IFDEBUG(D_CDUMP_REQ) + register int i; + + printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n", + buf, buflen, buflen); + for( i=0; i < buflen; ) { + printf("+%d: %x %x %x %x %x %x %x %x\n", + i, + *(buf+i), *(buf+i+1), *(buf+i+2), *(buf+i+3), + *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7)); + i+=8; + } + ENDDEBUG + IFDEBUG(D_CADDR) + printf("make_partial returns buf 0x%x size 0x%x bytes\n", + mtod(m, caddr_t), buflen); + ENDDEBUG + + if (buflen > MHLEN) + return E_CO_PNA_LONG; + + m->m_pkthdr.len = m->m_len = buflen; + lcp->lcd_facilities = m; + return 0; +} + +/* + * NAME: NSAPtoDTE() + * CALLED FROM: + * make_partial_x25_packet() + * FUNCTION and ARGUMENTS: + * get a DTE address from an NSAP-address (struct sockaddr_iso) + * (dst_octet) is the octet into which to begin stashing the DTE addr + * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr + * in the high-order nibble of dst_octet. 0 means low-order nibble. + * (addr) is the NSAP-address + * (flag) is true if the transport suffix is to become the + * last two digits of the DTE address + * A DTE address is a series of ASCII digits + * + * A DTE address may have leading zeros. The are significant. + * 1 digit per nibble, may be an odd number of nibbles. + * + * An NSAP-address has the DTE address in the IDI. Leading zeros are + * significant. Trailing hex f indicates the end of the DTE address. + * The IDI is a series of BCD digits, one per nibble. + * + * RETURNS + * # significant digits in the DTE address, -1 if error. + */ + +Static int +NSAPtoDTE(siso, sx25) + register struct sockaddr_iso *siso; + register struct sockaddr_x25 *sx25; +{ + int dtelen = -1; + + IFDEBUG(D_CADDR) + printf("NSAPtoDTE: nsap: %s\n", clnp_iso_addrp(&siso->siso_addr)); + ENDDEBUG + + if (siso->siso_data[0] == AFI_37) { + register char *out = sx25->x25_addr; + register char *in = siso->siso_data + 1; + register int nibble; + char *lim = siso->siso_data + siso->siso_nlen; + char *olim = out+15; + int lowNibble = 0; + + while (in < lim) { + nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30; + lowNibble ^= 1; + if (nibble != 0x3f && out < olim) + *out++ = nibble; + } + dtelen = out - sx25->x25_addr; + *out++ = 0; + } else { + /* error = iso_8208snparesolve(addr, x121string, &x121strlen);*/ + register struct rtentry *rt; + extern struct sockaddr_iso blank_siso; + struct sockaddr_iso nsiso; + + nsiso = blank_siso; + bcopy(nsiso.siso_data, siso->siso_data, + nsiso.siso_nlen = siso->siso_nlen); + if (rt = rtalloc1(&nsiso, 1)) { + register struct sockaddr_x25 *sxx = + (struct sockaddr_x25 *)rt->rt_gateway; + register char *in = sxx->x25_addr; + + rt->rt_use--; + if (sxx && sxx->x25_family == AF_CCITT) { + bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr)); + while (*in++) {} + dtelen = in - sxx->x25_addr; + } + } + } + return dtelen; +} + +/* + * NAME: FACILtoNSAP() + * CALLED FROM: + * parse_facil() + * FUNCTION and ARGUMENTS: + * Creates and NSAP in the sockaddr_iso (addr) from the + * x.25 facility found at buf - 1. + * RETURNS: + * 0 if ok, -1 if error. + */ + +Static int +FACILtoNSAP(addr, buf) + register u_char *buf; + register struct sockaddr_iso *addr; +{ + int len_in_nibbles = *++buf & 0x3f; + u_char buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */ + + IFDEBUG(D_CADDR) + printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n", + buf, buf_len, addr ); + ENDDEBUG + + len_in_nibbles = *buf & 0x3f; + /* despite the fact that X.25 makes us put a length in nibbles + * here, the NSAP-addrs are always in full octets + */ + switch (*buf++ & 0xc0) { + case 0: + /* Entire OSI NSAP address */ + bcopy((caddr_t)buf, addr->siso_data, addr->siso_nlen = buf_len); + break; + + case 40: + /* Partial OSI NSAP address, assume trailing */ + if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr)) + return -1; + bcopy((caddr_t)buf, TSEL(addr), buf_len); + addr->siso_nlen += buf_len; + break; + + default: + /* Rather than blow away the connection, just ignore and use + NSAP from DTE */; + } + return 0; +} + +Static +init_siso(siso) +register struct sockaddr_iso *siso; +{ + siso->siso_len = sizeof (*siso); + siso->siso_family = AF_ISO; + siso->siso_data[0] = AFI_37; + siso->siso_nlen = 8; +} + +/* + * NAME: DTEtoNSAP() + * CALLED FROM: + * parse_facil() + * FUNCTION and ARGUMENTS: + * Creates a type 37 NSAP in the sockaddr_iso (addr) + * from a DTE address found in a sockaddr_x25. + * + * RETURNS: + * 0 if ok; E* otherwise. + */ + +Static int +DTEtoNSAP(addr, sx) + struct sockaddr_iso *addr; + struct sockaddr_x25 *sx; +{ + register char *in, *out; + register int first; + int pad_tail = 0; + int src_len; + + + init_siso(addr); + in = sx->x25_addr; + src_len = strlen(in); + addr->siso_nlen = (src_len + 3) / 2; + out = addr->siso_data; + *out++ = 0x37; + if (src_len & 1) { + pad_tail = 0xf; + src_len++; + } + for (first = 0; src_len > 0; src_len--) { + first |= 0xf & *in++; + if (src_len & 1) { + *out++ = first; + first = 0; + } + else first <<= 4; + } + if (pad_tail) + out[-1] |= 0xf; + return 0; /* ok */ +} + +/* + * FUNCTION and ARGUMENTS: + * parses (buf_len) bytes beginning at (buf) and finds + * a called nsap, a calling nsap, and protocol identifier. + * RETURNS: + * 0 if ok, E* otherwise. + */ + +Static int +parse_facil(lcp, isop, buf, buf_len) + caddr_t buf; + u_char buf_len; /* in bytes */ + struct isopcb *isop; + struct pklcd *lcp; +{ + register int i; + register u_char *ptr = (u_char *)buf; + u_char *ptr_lim, *facil_lim; + int facil_param_len, facil_len; + + IFDEBUG(D_CADDR) + printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n", + lcp, isop, buf, buf_len); + dump_buf(buf, buf_len); + ENDDEBUG + + /* find the beginnings of the facility fields in buf + * by skipping over the called & calling DTE addresses + * i <- # nibbles in called + # nibbles in calling + * i += 1 so that an odd nibble gets rounded up to even + * before dividing by 2, then divide by two to get # octets + */ + i = (int)(*ptr >> 4) + (int)(*ptr&0xf); + i++; + ptr += i >> 1; + ptr ++; /* plus one for the DTE lengths byte */ + + /* ptr now is at facil_length field */ + facil_len = *ptr++; + facil_lim = ptr + facil_len; + IFDEBUG(D_CADDR) + printf("parse_facils: facil length is 0x%x\n", (int) facil_len); + ENDDEBUG + + while (ptr < facil_lim) { + /* get NSAP addresses from facilities */ + switch (*ptr++) { + case 0xcb: + /* calling NSAP */ + facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr); + break; + case 0xc9: + /* called NSAP */ + facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr); + break; + + /* from here to default are legit cases that I ignore */ + /* variable length */ + case 0xca: /* end-to-end transit delay negot */ + case 0xc6: /* network user id */ + case 0xc5: /* charging info : indicating monetary unit */ + case 0xc2: /* charging info : indicating segment count */ + case 0xc1: /* charging info : indicating call duration */ + case 0xc4: /* RPOA extended format */ + case 0xc3: /* call redirection notification */ + facil_param_len = 0; + break; + + /* 1 octet */ + case 0x0a: /* min. throughput class negot */ + case 0x02: /* throughput class */ + case 0x03: case 0x47: /* CUG shit */ + case 0x0b: /* expedited data negot */ + case 0x01: /* Fast select or reverse charging + (example of intelligent protocol design) */ + case 0x04: /* charging info : requesting service */ + case 0x08: /* called line addr modified notification */ + case 0x00: /* marker to indicate beginning of CCITT facils */ + facil_param_len = 1; + break; + + /* any 2 octets */ + case 0x42: /* pkt size */ + case 0x43: /* win size */ + case 0x44: /* RPOA basic format */ + case 0x41: /* bilateral CUG shit */ + case 0x49: /* transit delay selection and indication */ + facil_param_len = 2; + break; + + default: + printf( +"BOGUS FACILITY CODE facil_lim 0x%x facil_len %d, ptr 0x%x *ptr 0x%x\n", + facil_lim, facil_len, ptr - 1, ptr[-1]); + /* facil that we don't handle + return E_CO_HLI_REJI; */ + switch (ptr[-1] & 0xc0) { + case 0x00: facil_param_len = 1; break; + case 0x40: facil_param_len = 2; break; + case 0x80: facil_param_len = 3; break; + case 0xc0: facil_param_len = 0; break; + } + } + if (facil_param_len == -1) + return E_CO_REG_ICDA; + if (facil_param_len == 0) /* variable length */ + facil_param_len = (int)*ptr++; /* 1 + the real facil param */ + ptr += facil_param_len; + } + return 0; +} + +#endif /* TPCONS */ diff --git a/sys/netiso/if_eon.c b/sys/netiso/if_eon.c new file mode 100644 index 0000000..3c05133 --- /dev/null +++ b/sys/netiso/if_eon.c @@ -0,0 +1,609 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)if_eon.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $ + * + * EON rfc + * Layer between IP and CLNL + * + * TODO: + * Put together a current rfc986 address format and get the right offset + * for the nsel + */ + +#ifdef EON +#define NEON 1 + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/buf.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/errno.h> +#include <sys/types.h> + +#include <net/if.h> +#include <net/if_types.h> +#include <net/if_dl.h> +#include <net/netisr.h> +#include <net/route.h> +#include <machine/mtpr.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/in_var.h> +#include <netinet/ip.h> +#include <netinet/ip_var.h> +#include <netinet/if_ether.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#include <netiso/argo_debug.h> +#include <netiso/iso_errno.h> +#include <netiso/eonvar.h> + +extern struct timeval time; +extern struct ifnet loif; + +#define EOK 0 + +int eoninput(); +int eonoutput(); +int eonioctl(); +int eonattach(); +int eoninit(); +void eonrtrequest(); +struct ifnet eonif[1]; + +eonprotoinit() { + (void) eonattach(); +} + +struct eon_llinfo eon_llinfo; +#define PROBE_OK 0; + + +/* + * FUNCTION: eonattach + * + * PURPOSE: autoconf attach routine + * + * RETURNS: void + */ + +eonattach() +{ + register struct ifnet *ifp = eonif; + + IFDEBUG(D_EON) + printf("eonattach()\n"); + ENDDEBUG + ifp->if_unit = 0; + ifp->if_name = "eon"; + ifp->if_mtu = ETHERMTU; + /* since everything will go out over ether or token ring */ + + ifp->if_init = eoninit; + ifp->if_ioctl = eonioctl; + ifp->if_output = eonoutput; + ifp->if_type = IFT_EON; + ifp->if_addrlen = 5; + ifp->if_hdrlen = EONIPLEN; + ifp->if_flags = IFF_BROADCAST; + if_attach(ifp); + eonioctl(ifp, SIOCSIFADDR, (caddr_t)ifp->if_addrlist); + eon_llinfo.el_qhdr.link = + eon_llinfo.el_qhdr.rlink = &(eon_llinfo.el_qhdr); + + IFDEBUG(D_EON) + printf("eonattach()\n"); + ENDDEBUG +} + + +/* + * FUNCTION: eonioctl + * + * PURPOSE: io controls - ifconfig + * need commands to + * link-UP (core addr) (flags: ES, IS) + * link-DOWN (core addr) (flags: ES, IS) + * must be callable from kernel or user + * + * RETURNS: nothing + */ +eonioctl(ifp, cmd, data) + register struct ifnet *ifp; + int cmd; + register caddr_t data; +{ + int s = splimp(); + register int error = 0; + + IFDEBUG(D_EON) + printf("eonioctl (cmd 0x%x) \n", cmd); + ENDDEBUG + + switch (cmd) { + register struct ifaddr *ifa; + + case SIOCSIFADDR: + if (ifa = (struct ifaddr *)data) { + ifp->if_flags |= IFF_UP; + if (ifa->ifa_addr->sa_family != AF_LINK) + ifa->ifa_rtrequest = eonrtrequest; + } + break; + } + splx(s); + return(error); +} + + +eoniphdr(hdr, loc, ro, class, zero) +struct route *ro; +register struct eon_iphdr *hdr; +caddr_t loc; +{ + struct mbuf mhead; + register struct sockaddr_in *sin = (struct sockaddr_in *)&ro->ro_dst; + if (zero) { + bzero((caddr_t)hdr, sizeof (*hdr)); + bzero((caddr_t)ro, sizeof (*ro)); + } + sin->sin_family = AF_INET; + sin->sin_len = sizeof (*sin); + bcopy(loc, (caddr_t)&sin->sin_addr, sizeof(struct in_addr)); + /* + * If there is a cached route, + * check that it is to the same destination + * and is still up. If not, free it and try again. + */ + if (ro->ro_rt) { + struct sockaddr_in *dst = + (struct sockaddr_in *)rt_key(ro->ro_rt); + if ((ro->ro_rt->rt_flags & RTF_UP) == 0 || + sin->sin_addr.s_addr != dst->sin_addr.s_addr) { + RTFREE(ro->ro_rt); + ro->ro_rt = (struct rtentry *)0; + } + } + rtalloc(ro); + if (ro->ro_rt) + ro->ro_rt->rt_use++; + hdr->ei_ip.ip_dst = sin->sin_addr; + hdr->ei_ip.ip_p = IPPROTO_EON; + hdr->ei_ip.ip_ttl = MAXTTL; + hdr->ei_eh.eonh_class = class; + hdr->ei_eh.eonh_vers = EON_VERSION; + hdr->ei_eh.eonh_csum = 0; + mhead.m_data = (caddr_t) &hdr->ei_eh; + mhead.m_len = sizeof(struct eon_hdr); + mhead.m_next = 0; + IFDEBUG(D_EON) + printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", + &mhead, + _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); + ENDDEBUG + iso_gen_csum(&mhead, + _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); +} +/* + * FUNCTION: eonrtrequest + * + * PURPOSE: maintains list of direct eon recipients. + * sets up IP route for rest. + * + * RETURNS: nothing + */ +void +eonrtrequest(cmd, rt, gate) +register struct rtentry *rt; +register struct sockaddr *gate; +{ + unsigned long zerodst = 0; + caddr_t ipaddrloc = (caddr_t) &zerodst; + register struct eon_llinfo *el = (struct eon_llinfo *)rt->rt_llinfo; + + /* + * Common Housekeeping + */ + switch (cmd) { + case RTM_DELETE: + if (el) { + remque(&(el->el_qhdr)); + if (el->el_iproute.ro_rt) + RTFREE(el->el_iproute.ro_rt); + Free(el); + rt->rt_llinfo = 0; + } + return; + + case RTM_ADD: + case RTM_RESOLVE: + rt->rt_rmx.rmx_mtu = loif.if_mtu; /* unless better below */ + R_Malloc(el, struct eon_llinfo *, sizeof(*el)); + rt->rt_llinfo = (caddr_t)el; + if (el == 0) + return; + Bzero(el, sizeof(*el)); + insque(&(el->el_qhdr), &eon_llinfo.el_qhdr); + el->el_rt = rt; + break; + } + if (gate || (gate = rt->rt_gateway)) switch (gate->sa_family) { + case AF_LINK: +#define SDL(x) ((struct sockaddr_dl *)x) + if (SDL(gate)->sdl_alen == 1) + el->el_snpaoffset = *(u_char *)LLADDR(SDL(gate)); + else + ipaddrloc = LLADDR(SDL(gate)); + break; + case AF_INET: +#define SIN(x) ((struct sockaddr_in *)x) + ipaddrloc = (caddr_t) &SIN(gate)->sin_addr; + break; + default: + return; + } + el->el_flags |= RTF_UP; + eoniphdr(&el->el_ei, ipaddrloc, &el->el_iproute, EON_NORMAL_ADDR, 0); + if (el->el_iproute.ro_rt) + rt->rt_rmx.rmx_mtu = el->el_iproute.ro_rt->rt_rmx.rmx_mtu + - sizeof(el->el_ei); +} + +/* + * FUNCTION: eoninit + * + * PURPOSE: initialization + * + * RETURNS: nothing + */ + +eoninit(unit) + int unit; +{ + printf("eon driver-init eon%d\n", unit); +} + + +/* + * FUNCTION: eonoutput + * + * PURPOSE: prepend an eon header and hand to IP + * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device + * (m) is an mbuf *, *m is a CLNL packet + * (dst) is a destination address - have to interp. as + * multicast or broadcast or real address. + * + * RETURNS: unix error code + * + * NOTES: + * + */ +eonoutput(ifp, m, dst, rt) + struct ifnet *ifp; + register struct mbuf *m; /* packet */ + struct sockaddr_iso *dst; /* destination addr */ + struct rtentry *rt; +{ + register struct eon_llinfo *el; + register struct eon_iphdr *ei; + struct route *ro; + int datalen; + struct mbuf *mh; + int error = 0, class = 0, alen = 0; + caddr_t ipaddrloc; + static struct eon_iphdr eon_iphdr; + static struct route route; + + IFDEBUG(D_EON) + printf("eonoutput \n" ); + ENDDEBUG + + ifp->if_lastchange = time; + ifp->if_opackets++; + if (rt == 0 || (el = (struct eon_llinfo *)rt->rt_llinfo) == 0) { + if (dst->siso_family == AF_LINK) { + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)dst; + + ipaddrloc = LLADDR(sdl); + alen = sdl->sdl_alen; + } else if (dst->siso_family == AF_ISO && dst->siso_data[0] == AFI_SNA) { + alen = dst->siso_nlen - 1; + ipaddrloc = (caddr_t) dst->siso_data + 1; + } + switch (alen) { + case 5: + class = 4[(u_char *)ipaddrloc]; + case 4: + ro = &route; + ei = &eon_iphdr; + eoniphdr(ei, ipaddrloc, ro, class, 1); + goto send; + } +einval: + error = EINVAL; + goto flush; + } + if ((el->el_flags & RTF_UP) == 0) { + eonrtrequest(RTM_CHANGE, rt, (struct sockaddr *)0); + if ((el->el_flags & RTF_UP) == 0) { + error = EHOSTUNREACH; + goto flush; + } + } + if ((m->m_flags & M_PKTHDR) == 0) { + printf("eon: got non headered packet\n"); + goto einval; + } + ei = &el->el_ei; + ro = &el->el_iproute; + if (el->el_snpaoffset) { + if (dst->siso_family == AF_ISO) { + bcopy((caddr_t) &dst->siso_data[el->el_snpaoffset], + (caddr_t) &ei->ei_ip.ip_dst, sizeof(ei->ei_ip.ip_dst)); + } else + goto einval; + } +send: + /* put an eon_hdr in the buffer, prepended by an ip header */ + datalen = m->m_pkthdr.len + EONIPLEN; + MGETHDR(mh, M_DONTWAIT, MT_HEADER); + if(mh == (struct mbuf *)0) + goto flush; + mh->m_next = m; + m = mh; + MH_ALIGN(m, sizeof(struct eon_iphdr)); + m->m_len = sizeof(struct eon_iphdr); + ifp->if_obytes += + (ei->ei_ip.ip_len = (u_short)(m->m_pkthdr.len = datalen)); + *mtod(m, struct eon_iphdr *) = *ei; + + IFDEBUG(D_EON) + printf("eonoutput dst ip addr : %x\n", ei->ei_ip.ip_dst.s_addr); + printf("eonoutput ip_output : eonip header:\n"); + dump_buf(ei, sizeof(struct eon_iphdr)); + ENDDEBUG + + error = ip_output(m, (struct mbuf *)0, ro, 0, NULL); + m = 0; + if (error) { + ifp->if_oerrors++; + ifp->if_opackets--; + ifp->if_obytes -= datalen; + } +flush: + if (m) + m_freem(m); + return error; +} + +eoninput(m, iphlen) + register struct mbuf *m; + int iphlen; +{ + register struct eon_hdr *eonhdr; + register struct ip *iphdr; + struct ifnet *eonifp; + int s; + + eonifp = &eonif[0]; /* kludge - really want to give CLNP + * the ifp for eon, not for the real device + */ + + IFDEBUG(D_EON) + printf("eoninput() 0x%x m_data 0x%x m_len 0x%x dequeued\n", + m, m?m->m_data:0, m?m->m_len:0); + ENDDEBUG + + if (m == 0) + return; + if (iphlen > sizeof (struct ip)) + ip_stripoptions(m, (struct mbuf *)0); + if (m->m_len < EONIPLEN) { + if ((m = m_pullup(m, EONIPLEN)) == 0) { + IncStat(es_badhdr); +drop: + IFDEBUG(D_EON) + printf("eoninput: DROP \n" ); + ENDDEBUG + eonifp->if_ierrors ++; + m_freem(m); + return; + } + } + eonif->if_ibytes += m->m_pkthdr.len; + eonif->if_lastchange = time; + iphdr = mtod(m, struct ip *); + /* do a few checks for debugging */ + if( iphdr->ip_p != IPPROTO_EON ) { + IncStat(es_badhdr); + goto drop; + } + /* temporarily drop ip header from the mbuf */ + m->m_data += sizeof(struct ip); + eonhdr = mtod(m, struct eon_hdr *); + if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { + IncStat(es_badcsum); + goto drop; + } + m->m_data -= sizeof(struct ip); + + IFDEBUG(D_EON) + printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); + printf("eoninput: eon header:\n"); + dump_buf(eonhdr, sizeof(struct eon_hdr)); + ENDDEBUG + + /* checks for debugging */ + if( eonhdr->eonh_vers != EON_VERSION) { + IncStat(es_badhdr); + goto drop; + } + m->m_flags &= ~(M_BCAST|M_MCAST); + switch( eonhdr->eonh_class) { + case EON_BROADCAST: + IncStat(es_in_broad); + m->m_flags |= M_BCAST; + break; + case EON_NORMAL_ADDR: + IncStat(es_in_normal); + break; + case EON_MULTICAST_ES: + IncStat(es_in_multi_es); + m->m_flags |= M_MCAST; + break; + case EON_MULTICAST_IS: + IncStat(es_in_multi_is); + m->m_flags |= M_MCAST; + break; + } + eonifp->if_ipackets++; + + { + /* put it on the CLNP queue and set soft interrupt */ + struct ifqueue *ifq; + extern struct ifqueue clnlintrq; + + m->m_pkthdr.rcvif = eonifp; /* KLUDGE */ + IFDEBUG(D_EON) + printf("eoninput to clnl IFQ\n"); + ENDDEBUG + ifq = &clnlintrq; + s = splimp(); + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + eonifp->if_iqdrops++; + eonifp->if_ipackets--; + splx(s); + return; + } + IF_ENQUEUE(ifq, m); + IFDEBUG(D_EON) + printf( + "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_data 0x%x\n", + m, m->m_len, m->m_type, m->m_data); + dump_buf(mtod(m, caddr_t), m->m_len); + ENDDEBUG + schednetisr(NETISR_ISO); + splx(s); + } +} + +int +eonctlinput(cmd, sin) + int cmd; + struct sockaddr_in *sin; +{ + extern u_char inetctlerrmap[]; + + IFDEBUG(D_EON) + printf("eonctlinput: cmd 0x%x addr: ", cmd); + dump_isoaddr(sin); + printf("\n"); + ENDDEBUG + + if (cmd < 0 || cmd > PRC_NCMDS) + return 0; + + IncStat(es_icmp[cmd]); + switch (cmd) { + + case PRC_QUENCH: + case PRC_QUENCH2: + /* TODO: set the dec bit */ + break; + case PRC_TIMXCEED_REASS: + case PRC_ROUTEDEAD: + case PRC_HOSTUNREACH: + case PRC_UNREACH_NET: + case PRC_IFDOWN: + case PRC_UNREACH_HOST: + case PRC_HOSTDEAD: + case PRC_TIMXCEED_INTRANS: + /* TODO: mark the link down */ + break; + + case PRC_UNREACH_PROTOCOL: + case PRC_UNREACH_PORT: + case PRC_UNREACH_SRCFAIL: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + case PRC_MSGSIZE: + case PRC_PARAMPROB: + /* printf("eonctlinput: ICMP cmd 0x%x\n", cmd );*/ + break; + } + return 0; +} + +#endif diff --git a/sys/netiso/iso.c b/sys/netiso/iso.c new file mode 100644 index 0000000..cd64e68 --- /dev/null +++ b/sys/netiso/iso.c @@ -0,0 +1,919 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso.c 8.2 (Berkeley) 11/15/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: iso.c,v 4.11 88/09/19 14:58:35 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/iso.c,v $ + * + * iso.c: miscellaneous routines to support the iso address family + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/ioctl.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#include <netiso/iso_pcb.h> +#include <netiso/clnp.h> +#include <netiso/argo_debug.h> +#ifdef TUBA +#include <netiso/tuba_table.h> +#endif + +#ifdef ISO + +int iso_interfaces = 0; /* number of external interfaces */ +extern struct ifnet loif; /* loopback interface */ +int ether_output(); +void llc_rtrequest(); + +/* + * FUNCTION: iso_addrmatch1 + * + * PURPOSE: decide if the two iso_addrs passed are equal + * + * RETURNS: true if the addrs match, false if they do not + * + * SIDE EFFECTS: + * + * NOTES: + */ +iso_addrmatch1(isoaa, isoab) +register struct iso_addr *isoaa, *isoab; /* addresses to check */ +{ + u_int compare_len; + + IFDEBUG(D_ROUTE) + printf("iso_addrmatch1: comparing lengths: %d to %d\n", isoaa->isoa_len, + isoab->isoa_len); + printf("a:\n"); + dump_buf(isoaa->isoa_genaddr, isoaa->isoa_len); + printf("b:\n"); + dump_buf(isoab->isoa_genaddr, isoab->isoa_len); + ENDDEBUG + + if ((compare_len = isoaa->isoa_len) != isoab->isoa_len) { + IFDEBUG(D_ROUTE) + printf("iso_addrmatch1: returning false because of lengths\n"); + ENDDEBUG + return 0; + } + +#ifdef notdef + /* TODO : generalize this to all afis with masks */ + if( isoaa->isoa_afi == AFI_37 ) { + /* must not compare 2 least significant digits, or for + * that matter, the DSP + */ + compare_len = ADDR37_IDI_LEN - 1; + } +#endif + + IFDEBUG(D_ROUTE) + int i; + char *a, *b; + + a = isoaa->isoa_genaddr; + b = isoab->isoa_genaddr; + + for (i=0; i<compare_len; i++) { + printf("<%x=%x>", a[i]&0xff, b[i]&0xff); + if (a[i] != b[i]) { + printf("\naddrs are not equal at byte %d\n", i); + return(0); + } + } + printf("\n"); + printf("addrs are equal\n"); + return (1); + ENDDEBUG + return (!bcmp(isoaa->isoa_genaddr, isoab->isoa_genaddr, compare_len)); +} + +/* + * FUNCTION: iso_addrmatch + * + * PURPOSE: decide if the two sockadrr_isos passed are equal + * + * RETURNS: true if the addrs match, false if they do not + * + * SIDE EFFECTS: + * + * NOTES: + */ +iso_addrmatch(sisoa, sisob) +struct sockaddr_iso *sisoa, *sisob; /* addresses to check */ +{ + return(iso_addrmatch1(&sisoa->siso_addr, &sisob->siso_addr)); +} +#ifdef notdef +/* + * FUNCTION: iso_netmatch + * + * PURPOSE: similar to iso_addrmatch but takes sockaddr_iso + * as argument. + * + * RETURNS: true if same net, false if not + * + * SIDE EFFECTS: + * + * NOTES: + */ +iso_netmatch(sisoa, sisob) +struct sockaddr_iso *sisoa, *sisob; +{ + u_char bufa[sizeof(struct sockaddr_iso)]; + u_char bufb[sizeof(struct sockaddr_iso)]; + register int lena, lenb; + + lena = iso_netof(&sisoa->siso_addr, bufa); + lenb = iso_netof(&sisob->siso_addr, bufb); + + IFDEBUG(D_ROUTE) + printf("iso_netmatch: comparing lengths: %d to %d\n", lena, lenb); + printf("a:\n"); + dump_buf(bufa, lena); + printf("b:\n"); + dump_buf(bufb, lenb); + ENDDEBUG + + return ((lena == lenb) && (!bcmp(bufa, bufb, lena))); +} +#endif /* notdef */ + +/* + * FUNCTION: iso_hashchar + * + * PURPOSE: Hash all character in the buffer specified into + * a long. Return the long. + * + * RETURNS: The hash value. + * + * SIDE EFFECTS: + * + * NOTES: The hash is achieved by exclusive ORing 4 byte + * quantities. + */ +u_long +iso_hashchar(buf, len) +register caddr_t buf; /* buffer to pack from */ +register int len; /* length of buffer */ +{ + register u_long h = 0; + register int i; + + for (i=0; i<len; i+=4) { + register u_long l = 0; + + if ((len - i) < 4) { + /* buffer not multiple of 4 */ + switch (len - i) { + case 3: + l |= buf[i+2] << 8; + case 2: + l |= buf[i+1] << 16; + case 1: + l |= buf[i] << 24; + break; + default: + printf("iso_hashchar: unexpected value x%x\n", len - i); + break; + } + } else { + l |= buf[i] << 24; + l |= buf[i+1] << 16; + l |= buf[i+2] << 8; + l |= buf[i+3]; + } + + h ^= l; + } + + h ^= (u_long) (len % 4); + + return(h); +} +#ifdef notdef +/* + * FUNCTION: iso_hash + * + * PURPOSE: Fill in fields of afhash structure based upon addr passed. + * + * RETURNS: none + * + * SIDE EFFECTS: + * + * NOTES: + */ +iso_hash(siso, hp) +struct sockaddr_iso *siso; /* address to perform hash on */ +struct afhash *hp; /* RETURN: hash info here */ +{ + u_long buf[sizeof(struct sockaddr_iso)+1/4]; + register int bufsize; + + + bzero(buf, sizeof(buf)); + + bufsize = iso_netof(&siso->siso_addr, buf); + hp->afh_nethash = iso_hashchar((caddr_t)buf, bufsize); + + IFDEBUG(D_ROUTE) + printf("iso_hash: iso_netof: bufsize = %d\n", bufsize); + ENDDEBUG + + hp->afh_hosthash = iso_hashchar((caddr_t)&siso->siso_addr, + siso->siso_addr.isoa_len); + + IFDEBUG(D_ROUTE) + printf("iso_hash: %s: nethash = x%x, hosthash = x%x\n", + clnp_iso_addrp(&siso->siso_addr), hp->afh_nethash, + hp->afh_hosthash); + ENDDEBUG +} +/* + * FUNCTION: iso_netof + * + * PURPOSE: Extract the network portion of the iso address. + * The network portion of the iso address varies depending + * on the type of address. The network portion of the + * address will include the IDP. The network portion is: + * + * TYPE DESC + * t37 The AFI and x.121 (IDI) + * osinet The AFI, orgid, snetid + * rfc986 The AFI, vers and network part of + * internet address. + * + * RETURNS: number of bytes placed into buf. + * + * SIDE EFFECTS: + * + * NOTES: Buf is assumed to be big enough + */ +iso_netof(isoa, buf) +struct iso_addr *isoa; /* address */ +caddr_t buf; /* RESULT: network portion of address here */ +{ + u_int len = 1; /* length of afi */ + + switch (isoa->isoa_afi) { + case AFI_37: + /* + * Due to classic x.25 tunnel vision, there is no + * net portion of an x.121 address. For our purposes + * the AFI will do, so that all x.25 -type addresses + * map to the single x.25 SNPA. (Cannot have more than + * one, obviously). + */ + + break; + +/* case AFI_OSINET:*/ + case AFI_RFC986: { + u_short idi; /* value of idi */ + + /* osinet and rfc986 have idi in the same place */ + CTOH(isoa->rfc986_idi[0], isoa->rfc986_idi[1], idi); + + if (idi == IDI_OSINET) +/* + * Network portion of OSINET address can only be the IDI. Clearly, + * with one x25 interface, one could get to several orgids, and + * several snetids. + len += (ADDROSINET_IDI_LEN + OVLOSINET_ORGID_LEN + + OVLOSINET_SNETID_LEN); + */ + len += ADDROSINET_IDI_LEN; + else if (idi == IDI_RFC986) { + u_long inetaddr; + struct ovl_rfc986 *o986 = (struct ovl_rfc986 *)isoa; + + /* bump len to include idi and version (1 byte) */ + len += ADDRRFC986_IDI_LEN + 1; + + /* get inet addr long aligned */ + bcopy(o986->o986_inetaddr, &inetaddr, sizeof(inetaddr)); + inetaddr = ntohl(inetaddr); /* convert to host byte order */ + + IFDEBUG(D_ROUTE) + printf("iso_netof: isoa "); + dump_buf(isoa, sizeof(*isoa)); + printf("iso_netof: inetaddr 0x%x ", inetaddr); + ENDDEBUG + + /* bump len by size of network portion of inet address */ + if (IN_CLASSA(inetaddr)) { + len += 4-IN_CLASSA_NSHIFT/8; + IFDEBUG(D_ROUTE) + printf("iso_netof: class A net len is now %d\n", len); + ENDDEBUG + } else if (IN_CLASSB(inetaddr)) { + len += 4-IN_CLASSB_NSHIFT/8; + IFDEBUG(D_ROUTE) + printf("iso_netof: class B net len is now %d\n", len); + ENDDEBUG + } else { + len += 4-IN_CLASSC_NSHIFT/8; + IFDEBUG(D_ROUTE) + printf("iso_netof: class C net len is now %d\n", len); + ENDDEBUG + } + } else + len = 0; + } break; + + default: + len = 0; + } + + bcopy((caddr_t)isoa, buf, len); + IFDEBUG(D_ROUTE) + printf("iso_netof: isoa "); + dump_buf(isoa, len); + printf("iso_netof: net "); + dump_buf(buf, len); + ENDDEBUG + return len; +} +#endif /* notdef */ +/* + * Generic iso control operations (ioctl's). + * Ifp is 0 if not an interface-specific ioctl. + */ +/* ARGSUSED */ +iso_control(so, cmd, data, ifp) + struct socket *so; + int cmd; + caddr_t data; + register struct ifnet *ifp; +{ + register struct iso_ifreq *ifr = (struct iso_ifreq *)data; + register struct iso_ifaddr *ia = 0; + register struct ifaddr *ifa; + struct iso_ifaddr *oia; + struct iso_aliasreq *ifra = (struct iso_aliasreq *)data; + int error, hostIsNew, maskIsNew; + + /* + * Find address for this interface, if it exists. + */ + if (ifp) + for (ia = iso_ifaddr; ia; ia = ia->ia_next) + if (ia->ia_ifp == ifp) + break; + + switch (cmd) { + + case SIOCAIFADDR_ISO: + case SIOCDIFADDR_ISO: + if (ifra->ifra_addr.siso_family == AF_ISO) + for (oia = ia; ia; ia = ia->ia_next) { + if (ia->ia_ifp == ifp && + SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr)) + break; + } + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); + if (ifp == 0) + panic("iso_control"); + if (ia == (struct iso_ifaddr *)0) { + struct iso_ifaddr *nia; + if (cmd == SIOCDIFADDR_ISO) + return (EADDRNOTAVAIL); +#ifdef TUBA + /* XXXXXX can't be done in the proto init routines */ + if (tuba_tree == 0) + tuba_table_init(); +#endif + MALLOC(nia, struct iso_ifaddr *, sizeof(*nia), + M_IFADDR, M_WAITOK); + if (nia == (struct iso_ifaddr *)0) + return (ENOBUFS); + bzero((caddr_t)nia, sizeof(*nia)); + if (ia = iso_ifaddr) { + for ( ; ia->ia_next; ia = ia->ia_next) + ; + ia->ia_next = nia; + } else + iso_ifaddr = nia; + ia = nia; + if (ifa = ifp->if_addrlist) { + for ( ; ifa->ifa_next; ifa = ifa->ifa_next) + ; + ifa->ifa_next = (struct ifaddr *) ia; + } else + ifp->if_addrlist = (struct ifaddr *) ia; + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + ia->ia_ifa.ifa_dstaddr + = (struct sockaddr *)&ia->ia_dstaddr; + ia->ia_ifa.ifa_netmask + = (struct sockaddr *)&ia->ia_sockmask; + ia->ia_ifp = ifp; + if (ifp != &loif) + iso_interfaces++; + } + break; + +#define cmdbyte(x) (((x) >> 8) & 0xff) + default: + if (cmdbyte(cmd) == 'a') + return (snpac_ioctl(so, cmd, data)); + if (ia == (struct iso_ifaddr *)0) + return (EADDRNOTAVAIL); + break; + } + switch (cmd) { + + case SIOCGIFADDR_ISO: + ifr->ifr_Addr = ia->ia_addr; + break; + + case SIOCGIFDSTADDR_ISO: + if ((ifp->if_flags & IFF_POINTOPOINT) == 0) + return (EINVAL); + ifr->ifr_Addr = ia->ia_dstaddr; + break; + + case SIOCGIFNETMASK_ISO: + ifr->ifr_Addr = ia->ia_sockmask; + break; + + case SIOCAIFADDR_ISO: + maskIsNew = 0; hostIsNew = 1; error = 0; + if (ia->ia_addr.siso_family == AF_ISO) { + if (ifra->ifra_addr.siso_len == 0) { + ifra->ifra_addr = ia->ia_addr; + hostIsNew = 0; + } else if (SAME_ISOADDR(&ia->ia_addr, &ifra->ifra_addr)) + hostIsNew = 0; + } + if (ifra->ifra_mask.siso_len) { + iso_ifscrub(ifp, ia); + ia->ia_sockmask = ifra->ifra_mask; + maskIsNew = 1; + } + if ((ifp->if_flags & IFF_POINTOPOINT) && + (ifra->ifra_dstaddr.siso_family == AF_ISO)) { + iso_ifscrub(ifp, ia); + ia->ia_dstaddr = ifra->ifra_dstaddr; + maskIsNew = 1; /* We lie; but the effect's the same */ + } + if (ifra->ifra_addr.siso_family == AF_ISO && + (hostIsNew || maskIsNew)) { + error = iso_ifinit(ifp, ia, &ifra->ifra_addr, 0); + } + if (ifra->ifra_snpaoffset) + ia->ia_snpaoffset = ifra->ifra_snpaoffset; + return (error); + + case SIOCDIFADDR_ISO: + iso_ifscrub(ifp, ia); + if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) + ifp->if_addrlist = ifa->ifa_next; + else { + while (ifa->ifa_next && + (ifa->ifa_next != (struct ifaddr *)ia)) + ifa = ifa->ifa_next; + if (ifa->ifa_next) + ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; + else + printf("Couldn't unlink isoifaddr from ifp\n"); + } + oia = ia; + if (oia == (ia = iso_ifaddr)) { + iso_ifaddr = ia->ia_next; + } else { + while (ia->ia_next && (ia->ia_next != oia)) { + ia = ia->ia_next; + } + if (ia->ia_next) + ia->ia_next = oia->ia_next; + else + printf("Didn't unlink isoifadr from list\n"); + } + IFAFREE((&oia->ia_ifa)); + break; + + default: + if (ifp == 0 || ifp->if_ioctl == 0) + return (EOPNOTSUPP); + return ((*ifp->if_ioctl)(ifp, cmd, data)); + } + return (0); +} + +/* + * Delete any existing route for an interface. + */ +iso_ifscrub(ifp, ia) + register struct ifnet *ifp; + register struct iso_ifaddr *ia; +{ + int nsellength = ia->ia_addr.siso_tlen; + if ((ia->ia_flags & IFA_ROUTE) == 0) + return; + ia->ia_addr.siso_tlen = 0; + if (ifp->if_flags & IFF_LOOPBACK) + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + else if (ifp->if_flags & IFF_POINTOPOINT) + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); + else { + rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); + } + ia->ia_addr.siso_tlen = nsellength; + ia->ia_flags &= ~IFA_ROUTE; +} + +/* + * Initialize an interface's internet address + * and routing table entry. + */ +iso_ifinit(ifp, ia, siso, scrub) + register struct ifnet *ifp; + register struct iso_ifaddr *ia; + struct sockaddr_iso *siso; +{ + struct sockaddr_iso oldaddr; + int s = splimp(), error, nsellength; + + oldaddr = ia->ia_addr; + ia->ia_addr = *siso; + /* + * Give the interface a chance to initialize + * if this is its first address, + * and to validate the address if necessary. + */ + if (ifp->if_ioctl && + (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { + splx(s); + ia->ia_addr = oldaddr; + return (error); + } + if (scrub) { + ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; + iso_ifscrub(ifp, ia); + ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; + } + /* XXX -- The following is here temporarily out of laziness + in not changing every ethernet driver's if_ioctl routine */ + if (ifp->if_output == ether_output) { + ia->ia_ifa.ifa_rtrequest = llc_rtrequest; + ia->ia_ifa.ifa_flags |= RTF_CLONING; + } + /* + * Add route for the network. + */ + nsellength = ia->ia_addr.siso_tlen; + ia->ia_addr.siso_tlen = 0; + if (ifp->if_flags & IFF_LOOPBACK) { + ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; + error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); + } else if (ifp->if_flags & IFF_POINTOPOINT && + ia->ia_dstaddr.siso_family == AF_ISO) + error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); + else { + rt_maskedcopy(ia->ia_ifa.ifa_addr, ia->ia_ifa.ifa_dstaddr, + ia->ia_ifa.ifa_netmask); + ia->ia_dstaddr.siso_nlen = + min(ia->ia_addr.siso_nlen, (ia->ia_sockmask.siso_len - 6)); + error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP); + } + ia->ia_addr.siso_tlen = nsellength; + ia->ia_flags |= IFA_ROUTE; + splx(s); + return (error); +} +#ifdef notdef + +struct ifaddr * +iso_ifwithidi(addr) + register struct sockaddr *addr; +{ + register struct ifnet *ifp; + register struct ifaddr *ifa; + register u_int af = addr->sa_family; + + if (af != AF_ISO) + return (0); + IFDEBUG(D_ROUTE) + printf(">>> iso_ifwithidi addr\n"); + dump_isoaddr( (struct sockaddr_iso *)(addr)); + printf("\n"); + ENDDEBUG + for (ifp = ifnet; ifp; ifp = ifp->if_next) { + IFDEBUG(D_ROUTE) + printf("iso_ifwithidi ifnet %s\n", ifp->if_name); + ENDDEBUG + for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) { + IFDEBUG(D_ROUTE) + printf("iso_ifwithidi address "); + dump_isoaddr( (struct sockaddr_iso *)(ifa->ifa_addr)); + ENDDEBUG + if (ifa->ifa_addr->sa_family != addr->sa_family) + continue; + +#define IFA_SIS(ifa)\ + ((struct sockaddr_iso *)((ifa)->ifa_addr)) + + IFDEBUG(D_ROUTE) + printf(" af same, args to iso_eqtype:\n"); + printf("0x%x ", IFA_SIS(ifa)->siso_addr); + printf(" 0x%x\n", + &(((struct sockaddr_iso *)addr)->siso_addr)); + ENDDEBUG + + if (iso_eqtype(&(IFA_SIS(ifa)->siso_addr), + &(((struct sockaddr_iso *)addr)->siso_addr))) { + IFDEBUG(D_ROUTE) + printf("ifa_ifwithidi: ifa found\n"); + ENDDEBUG + return (ifa); + } + IFDEBUG(D_ROUTE) + printf(" iso_eqtype failed\n"); + ENDDEBUG + } + } + return ((struct ifaddr *)0); +} + +#endif /* notdef */ +/* + * FUNCTION: iso_ck_addr + * + * PURPOSE: return true if the iso_addr passed is + * within the legal size limit for an iso address. + * + * RETURNS: true or false + * + * SIDE EFFECTS: + * + */ +iso_ck_addr(isoa) +struct iso_addr *isoa; /* address to check */ +{ + return (isoa->isoa_len <= 20); + +} + +#ifdef notdef +/* + * FUNCTION: iso_eqtype + * + * PURPOSE: Determine if two iso addresses are of the same type. + * This is flaky. Really we should consider all type 47 addrs to be the + * same - but there do exist different structures for 47 addrs. + * Gosip adds a 3rd. + * + * RETURNS: true if the addresses are the same type + * + * SIDE EFFECTS: + * + * NOTES: By type, I mean rfc986, t37, or osinet + * + * This will first compare afis. If they match, then + * if the addr is not t37, the idis must be compared. + */ +iso_eqtype(isoaa, isoab) +struct iso_addr *isoaa; /* first addr to check */ +struct iso_addr *isoab; /* other addr to check */ +{ + if (isoaa->isoa_afi == isoab->isoa_afi) { + if (isoaa->isoa_afi == AFI_37) + return(1); + else + return (!bcmp(&isoaa->isoa_u, &isoab->isoa_u, 2)); + } + return(0); +} +#endif /* notdef */ +/* + * FUNCTION: iso_localifa() + * + * PURPOSE: Find an interface addresss having a given destination + * or at least matching the net. + * + * RETURNS: ptr to an interface address + * + * SIDE EFFECTS: + * + * NOTES: + */ +struct iso_ifaddr * +iso_localifa(siso) + register struct sockaddr_iso *siso; +{ + register struct iso_ifaddr *ia; + register char *cp1, *cp2, *cp3; + register struct ifnet *ifp; + struct iso_ifaddr *ia_maybe = 0; + /* + * We make one pass looking for both net matches and an exact + * dst addr. + */ + for (ia = iso_ifaddr; ia; ia = ia->ia_next) { + if ((ifp = ia->ia_ifp) == 0 || ((ifp->if_flags & IFF_UP) == 0)) + continue; + if (ifp->if_flags & IFF_POINTOPOINT) { + if ((ia->ia_dstaddr.siso_family == AF_ISO) && + SAME_ISOADDR(&ia->ia_dstaddr, siso)) + return (ia); + else + if (SAME_ISOADDR(&ia->ia_addr, siso)) + ia_maybe = ia; + continue; + } + if (ia->ia_sockmask.siso_len) { + char *cplim = ia->ia_sockmask.siso_len + (char *)&ia->ia_sockmask; + cp1 = ia->ia_sockmask.siso_data; + cp2 = siso->siso_data; + cp3 = ia->ia_addr.siso_data; + while (cp1 < cplim) + if (*cp1++ & (*cp2++ ^ *cp3++)) + goto next; + ia_maybe = ia; + } + if (SAME_ISOADDR(&ia->ia_addr, siso)) + return ia; + next:; + } + return ia_maybe; +} + +#ifdef TPCONS +#include <netiso/cons.h> +#endif /* TPCONS */ +/* + * FUNCTION: iso_nlctloutput + * + * PURPOSE: Set options at the network level + * + * RETURNS: E* + * + * SIDE EFFECTS: + * + * NOTES: This could embody some of the functions of + * rclnp_ctloutput and cons_ctloutput. + */ +iso_nlctloutput(cmd, optname, pcb, m) +int cmd; /* command:set or get */ +int optname; /* option of interest */ +caddr_t pcb; /* nl pcb */ +struct mbuf *m; /* data for set, buffer for get */ +{ + struct isopcb *isop = (struct isopcb *)pcb; + int error = 0; /* return value */ + caddr_t data; /* data for option */ + int data_len; /* data's length */ + + IFDEBUG(D_ISO) + printf("iso_nlctloutput: cmd %x, opt %x, pcb %x, m %x\n", + cmd, optname, pcb, m); + ENDDEBUG + + if ((cmd != PRCO_GETOPT) && (cmd != PRCO_SETOPT)) + return(EOPNOTSUPP); + + data = mtod(m, caddr_t); + data_len = (m)->m_len; + + IFDEBUG(D_ISO) + printf("iso_nlctloutput: data is:\n"); + dump_buf(data, data_len); + ENDDEBUG + + switch (optname) { + +#ifdef TPCONS + case CONSOPT_X25CRUD: + if (cmd == PRCO_GETOPT) { + error = EOPNOTSUPP; + break; + } + + if (data_len > MAXX25CRUDLEN) { + error = EINVAL; + break; + } + + IFDEBUG(D_ISO) + printf("iso_nlctloutput: setting x25 crud\n"); + ENDDEBUG + + bcopy(data, (caddr_t)isop->isop_x25crud, (unsigned)data_len); + isop->isop_x25crud_len = data_len; + break; +#endif /* TPCONS */ + + default: + error = EOPNOTSUPP; + } + if (cmd == PRCO_SETOPT) + m_freem(m); + return error; +} +#endif /* ISO */ + +#ifdef ARGO_DEBUG + +/* + * FUNCTION: dump_isoaddr + * + * PURPOSE: debugging + * + * RETURNS: nada + * + */ +dump_isoaddr(s) + struct sockaddr_iso *s; +{ + char *clnp_saddr_isop(); + register int i; + + if( s->siso_family == AF_ISO) { + printf("ISO address: suffixlen %d, %s\n", + s->siso_tlen, clnp_saddr_isop(s)); + } else if( s->siso_family == AF_INET) { + /* hack */ + struct sockaddr_in *sin = (struct sockaddr_in *)s; + + printf("%d.%d.%d.%d: %d", + (sin->sin_addr.s_addr>>24)&0xff, + (sin->sin_addr.s_addr>>16)&0xff, + (sin->sin_addr.s_addr>>8)&0xff, + (sin->sin_addr.s_addr)&0xff, + sin->sin_port); + } +} + +#endif /* ARGO_DEBUG */ diff --git a/sys/netiso/iso.h b/sys/netiso/iso.h new file mode 100644 index 0000000..9237e6a --- /dev/null +++ b/sys/netiso/iso.h @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: iso.h,v 4.9 88/09/11 18:06:38 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/iso.h,v $ */ + +#ifndef __ISO__ +#define __ISO__ + +/* + * Return true if this is a multicast address + * This assumes that the bit transmission is lsb first. This + * assumption is valid for 802.3 but not 802.5. There is a + * kludge to get around this for 802.5 -- see if_lan.c + * where subnetwork header is setup. + */ +#define IS_MULTICAST(snpa)\ + ((snpa)[0] & 0x01) + +/* + * Protocols + */ +#define ISOPROTO_TCP 6 /* IETF experiment */ +#define ISOPROTO_UDP 17 /* IETF experiment */ +#define ISOPROTO_TP0 25 /* connection oriented transport protocol */ +#define ISOPROTO_TP1 26 /* not implemented */ +#define ISOPROTO_TP2 27 /* not implemented */ +#define ISOPROTO_TP3 28 /* not implemented */ +#define ISOPROTO_TP4 29 /* connection oriented transport protocol */ +#define ISOPROTO_TP ISOPROTO_TP4 /* tp-4 with negotiation */ +#define ISOPROTO_CLTP 30 /* connectionless transport (not yet impl.) */ +#define ISOPROTO_CLNP 31 /* connectionless internetworking protocol */ +#define ISOPROTO_X25 32 /* cons */ +#define ISOPROTO_INACT_NL 33 /* inactive network layer! */ +#define ISOPROTO_ESIS 34 /* ES-IS protocol */ +#define ISOPROTO_INTRAISIS 35 /* IS-IS protocol */ +#define ISOPROTO_IDRP 36 /* Interdomain Routing Protocol */ + +#define ISOPROTO_RAW 255 /* raw clnp */ +#define ISOPROTO_MAX 256 + +#define ISO_PORT_RESERVED 1024 +#define ISO_PORT_USERRESERVED 5000 +/* + * Port/socket numbers: standard network functions + * NOT PRESENTLY USED + */ +#define ISO_PORT_MAINT 501 +#define ISO_PORT_ECHO 507 +#define ISO_PORT_DISCARD 509 +#define ISO_PORT_SYSTAT 511 +#define ISO_PORT_NETSTAT 515 +/* + * Port/socket numbers: non-standard application functions + */ +#define ISO_PORT_LOGIN 513 +/* + * Port/socket numbers: public use + */ +#define ISO_PORT_PUBLIC 1024 /* high bit set --> public */ + +/* + * Network layer protocol identifiers + */ +#define ISO8473_CLNP 0x81 +#define ISO9542_ESIS 0x82 +#define ISO9542X25_ESIS 0x8a +#define ISO10589_ISIS 0x83 +#define ISO8878A_CONS 0x84 +#define ISO10747_IDRP 0x85 + + +#ifndef IN_CLASSA_NET +#include <netinet/in.h> +#endif /* IN_CLASSA_NET */ + + + +/* The following looks like a sockaddr + * to facilitate using tree lookup routines */ +struct iso_addr { + u_char isoa_len; /* length (in bytes) */ + char isoa_genaddr[20]; /* general opaque address */ +}; + +struct sockaddr_iso { + u_char siso_len; /* length */ + u_char siso_family; /* family */ + u_char siso_plen; /* presentation selector length */ + u_char siso_slen; /* session selector length */ + u_char siso_tlen; /* transport selector length */ + struct iso_addr siso_addr; /* network address */ + u_char siso_pad[6]; /* space for gosip v2 sels */ + /* makes struct 32 bytes long */ +}; +#define siso_nlen siso_addr.isoa_len +#define siso_data siso_addr.isoa_genaddr + +#define TSEL(s) ((caddr_t)((s)->siso_data + (s)->siso_nlen)) + +#define SAME_ISOADDR(a, b) \ + (bcmp((a)->siso_data, (b)->siso_data, (unsigned)(a)->siso_nlen)==0) +/* + * The following are specific values for siso->siso_data[0], + * otherwise known as the AFI: + */ +#define AFI_37 0x37 /* bcd of "37" */ +#define AFI_OSINET 0x47 /* bcd of "47" */ +#define AFI_RFC986 0x47 /* bcd of "47" */ +#define AFI_SNA 0x00 /* SubNetwork Address; invalid really...*/ + +#ifdef KERNEL + +extern int iso_netmatch(); +extern int iso_hash(); +extern int iso_addrmatch(); +extern struct iso_ifaddr *iso_iaonnetof(); +extern struct domain isodomain; +extern struct protosw isosw[]; + +#else +/* user utilities definitions from the iso library */ + +#include <sys/cdefs.h> + +__BEGIN_DECLS +struct iso_addr *iso_addr __P((const char *)); +char *iso_ntoa __P((const struct iso_addr *)); + +/* THESE DON'T EXIST YET */ +struct hostent *iso_gethostbyname(), *iso_gethostbyaddr(); +__END_DECLS + +#endif /* KERNEL */ + +#define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) +#endif /* __ISO__ */ diff --git a/sys/netiso/iso_chksum.c b/sys/netiso/iso_chksum.c new file mode 100644 index 0000000..5b1aae5 --- /dev/null +++ b/sys/netiso/iso_chksum.c @@ -0,0 +1,360 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_chksum.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: iso_chksum.c,v 4.7 88/07/29 15:31:26 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/iso_chksum.c,v $ + * + * ISO CHECKSUM + * + * The checksum generation and check routines are here. + * The checksum is 2 bytes such that the sum of all the bytes b(i) == 0 + * and the sum of i * b(i) == 0. + * The whole thing is complicated by the fact that the data are in mbuf + * chains. + * Furthermore, there is the possibility of wraparound in the running + * sums after adding up 4102 octets. In order to avoid doing a mod + * operation after EACH add, we have restricted this implementation to + * negotiating a maximum of 4096-octets per TPDU (for the transport layer). + * The routine iso_check_csum doesn't need to know where the checksum + * octets are. + * The routine iso_gen_csum takes a pointer to an mbuf chain (logically + * a chunk of data), an offset into the chunk at which the 2 octets are to + * be stuffed, and the length of the chunk. The 2 octets have to be + * logically adjacent, but may be physically located in separate mbufs. + */ + +#ifdef ISO +#include <netiso/argo_debug.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#endif /* ISO */ + +#ifndef MNULL +#define MNULL (struct mbuf *)0 +#endif /* MNULL */ + +/* + * FUNCTION: iso_check_csum + * + * PURPOSE: To check the checksum of the packet in the mbuf chain (m). + * The total length of the packet is (len). + * Called from tp_input() and clnp_intr() + * + * RETURNS: TRUE (something non-zero) if there is a checksum error, + * FALSE if there was NO checksum error. + * + * SIDE EFFECTS: none + * + * NOTES: It might be possible to gain something by optimizing + * this routine (unrolling loops, etc). But it is such + * a horrible thing to fiddle with anyway, it probably + * isn't worth it. + */ +int +iso_check_csum(m, len) + struct mbuf *m; + int len; +{ + register u_char *p = mtod(m, u_char *); + register u_long c0=0, c1=0; + register int i=0; + int cum = 0; /* cumulative length */ + int l; + + l = len; + len = min(m->m_len, len); + i = 0; + + IFDEBUG(D_CHKSUM) + printf("iso_check_csum: m x%x, l x%x, m->m_len x%x\n", m, l, m->m_len); + ENDDEBUG + + while( i<l ) { + cum += len; + while (i<cum) { + c0 = c0 + *(p++); + c1 += c0; + i++; + } + if(i < l) { + m = m->m_next; + IFDEBUG(D_CHKSUM) + printf("iso_check_csum: new mbuf\n"); + if(l-i < m->m_len) + printf( + "bad mbuf chain in check csum l 0x%x i 0x%x m_data 0x%x", + l,i,m->m_data); + ENDDEBUG + ASSERT( m != MNULL); + len = min( m->m_len, l-i); + p = mtod(m, u_char *); + } + } + if ( ((int)c0 % 255) || ((int)c1 % 255) ) { + IFDEBUG(D_CHKSUM) + printf("BAD iso_check_csum l 0x%x cum 0x%x len 0x%x, i 0x%x", + l, cum, len, i); + ENDDEBUG + return ((int)c0 % 255)<<8 | ((int)c1 % 255); + } + return 0; +} + +/* + * FUNCTION: iso_gen_csum + * + * PURPOSE: To generate the checksum of the packet in the mbuf chain (m). + * The first of the 2 (logically) adjacent checksum bytes + * (x and y) go at offset (n). + * (n) is an offset relative to the beginning of the data, + * not the beginning of the mbuf. + * (l) is the length of the total mbuf chain's data. + * Called from tp_emit(), tp_error_emit() + * clnp_emit_er(), clnp_forward(), clnp_output(). + * + * RETURNS: Rien + * + * SIDE EFFECTS: Puts the 2 checksum bytes into the packet. + * + * NOTES: Ditto the note for iso_check_csum(). + */ + +void +iso_gen_csum(m,n,l) + struct mbuf *m; + int n; /* offset of 2 checksum bytes */ + int l; +{ + register u_char *p = mtod(m, u_char *); + register int c0=0, c1=0; + register int i=0; + int loc = n++, len=0; /* n is position, loc is offset */ + u_char *xloc; + u_char *yloc; + int cum=0; /* cum == cumulative length */ + + IFDEBUG(D_CHKSUM) + printf("enter gen csum m 0x%x n 0x%x l 0x%x\n",m, n-1 ,l ); + ENDDEBUG + + while(i < l) { + len = min(m->m_len, CLBYTES); + /* RAH: don't cksum more than l bytes */ + len = min(len, l - i); + + cum +=len; + p = mtod(m, u_char *); + + if(loc>=0) { + if (loc < len) { + xloc = loc + mtod(m, u_char *); + IFDEBUG(D_CHKSUM) + printf("1: zeroing xloc 0x%x loc 0x%x\n",xloc, loc ); + ENDDEBUG + *xloc = (u_char)0; + if (loc+1 < len) { + /* both xloc and yloc are in same mbuf */ + yloc = 1 + xloc; + IFDEBUG(D_CHKSUM) + printf("2: zeroing yloc 0x%x loc 0x%x\n",yloc, loc ); + ENDDEBUG + *yloc = (u_char)0; + } else { + /* crosses boundary of mbufs */ + yloc = mtod(m->m_next, u_char *); + IFDEBUG(D_CHKSUM) + printf("3: zeroing yloc 0x%x \n",yloc ); + ENDDEBUG + *yloc = (u_char)0; + } + } + loc -= len; + } + + while(i < cum) { + c0 = (c0 + *p); + c1 += c0 ; + i++; + p++; + } + m = m->m_next; + } + IFDEBUG(D_CHKSUM) + printf("gen csum final xloc 0x%x yloc 0x%x\n",xloc, yloc ); + ENDDEBUG + + c1 = (((c0 * (l-n))-c1)%255) ; + *xloc = (u_char) ((c1 < 0)? c1+255 : c1); + + c1 = (-(int)(c1+c0))%255; + *yloc = (u_char) (c1 < 0? c1 + 255 : c1); + + IFDEBUG(D_CHKSUM) + printf("gen csum end \n"); + ENDDEBUG +} + +/* + * FUNCTION: m_datalen + * + * PURPOSE: returns length of the mbuf chain. + * used all over the iso code. + * + * RETURNS: integer + * + * SIDE EFFECTS: none + * + * NOTES: + */ + +int +m_datalen (m) + register struct mbuf *m; +{ + register int datalen; + + for (datalen = 0; m; m = m->m_next) + datalen += m->m_len; + return datalen; +} + +int +m_compress(in, out) + register struct mbuf *in, **out; +{ + register int datalen = 0; + int s = splimp(); + + if( in->m_next == MNULL ) { + *out = in; + IFDEBUG(D_REQUEST) + printf("m_compress returning 0x%x: A\n", in->m_len); + ENDDEBUG + splx(s); + return in->m_len; + } + MGET((*out), M_DONTWAIT, MT_DATA); + if((*out) == MNULL) { + *out = in; + IFDEBUG(D_REQUEST) + printf("m_compress returning -1: B\n"); + ENDDEBUG + splx(s); + return -1; + } + (*out)->m_len = 0; + (*out)->m_act = MNULL; + + while (in) { + IFDEBUG(D_REQUEST) + printf("m_compress in 0x%x *out 0x%x\n", in, *out); + printf("m_compress in: len 0x%x, off 0x%x\n", in->m_len, in->m_data); + printf("m_compress *out: len 0x%x, off 0x%x\n", (*out)->m_len, + (*out)->m_data); + ENDDEBUG + if (in->m_flags & M_EXT) { + ASSERT(in->m_len == 0); + } + if ( in->m_len == 0) { + in = in->m_next; + continue; + } + if (((*out)->m_flags & M_EXT) == 0) { + int len; + + len = M_TRAILINGSPACE(*out); + len = min(len, in->m_len); + datalen += len; + + IFDEBUG(D_REQUEST) + printf("m_compress copying len %d\n", len); + ENDDEBUG + bcopy(mtod(in, caddr_t), mtod((*out), caddr_t) + (*out)->m_len, + (unsigned)len); + + (*out)->m_len += len; + in->m_len -= len; + continue; + } else { + /* (*out) is full */ + if(( (*out)->m_next = m_get(M_DONTWAIT, MT_DATA) ) == MNULL) { + m_freem(*out); + *out = in; + IFDEBUG(D_REQUEST) + printf("m_compress returning -1: B\n"); + ENDDEBUG + splx(s); + return -1; + } + (*out)->m_len = 0; + (*out)->m_act = MNULL; + *out = (*out)->m_next; + } + } + m_freem(in); + IFDEBUG(D_REQUEST) + printf("m_compress returning 0x%x: A\n", datalen); + ENDDEBUG + splx(s); + return datalen; +} diff --git a/sys/netiso/iso_errno.h b/sys/netiso/iso_errno.h new file mode 100644 index 0000000..0d75589c --- /dev/null +++ b/sys/netiso/iso_errno.h @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_errno.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#ifndef __ISO_ERRNO__ +#define __ISO_ERRNO__ + +#define ISO_ERROR_MASK 0x8000 +#define BSD_ERROR_MASK 0x0000 +#define TP_ERROR_MASK 0x8800 /* transport layer */ +#define CONL_ERROR_MASK 0x8400 /* co network layer */ +#define CLNL_ERROR_MASK 0x8200 /* cl network layer */ +#define TP_ERROR_SNDC 0x10000 /* kludge to force DC's on certain errors */ + +#define E_CO_NOERROR (CONL_ERROR_MASK | 0x0) /* no add'l info */ + +/******************************************************************************/ +/* */ +/* */ +/* Transport Layer */ +/* */ +/* */ +/******************************************************************************/ + +#define E_TP_DR_NO_REAS (TP_ERROR_MASK | 0x0) /* dr reason not specified*/ +#define E_TP_CONGEST (TP_ERROR_MASK | 0x1) /* dr reason congestion */ +#define E_TP_NO_SESSION (TP_ERROR_MASK | 0x2) /* dr reason no sess ent */ +#define E_TP_ADDR_UNK (TP_ERROR_MASK | 0x3) /* dr reason addr unknown */ + +#define E_TP_ER_NO_REAS (TP_ERROR_MASK | 0x40) /* er reas not specified */ +#define E_TP_INV_PCODE (TP_ERROR_MASK | 0x41) /* er reas invalid parm code */ +#define E_TP_INV_TPDU (TP_ERROR_MASK | 0x42) /* er reas invalid tpdu type */ +#define E_TP_INV_PVAL (TP_ERROR_MASK | 0x43) /* er reas invalid parm value*/ + +#define E_TP_NORMAL_DISC (TP_ERROR_MASK | 0x80) /* dr reas normal disc */ +#define E_TP_CONGEST_2 (TP_ERROR_MASK | 0x81) /* dr reason congestion */ +#define E_TP_NEGOT_FAILED (TP_ERROR_MASK | 0x82) /* dr negotiation failed */ +#define E_TP_DUPL_SRCREF (TP_ERROR_MASK | 0x83) /* dr duplicate src ref */ +#define E_TP_MISM_REFS (TP_ERROR_MASK | 0x84) /* dr mismatched references*/ +#define E_TP_PROTO_ERR (TP_ERROR_MASK | 0x85) /* dr protocol error*/ +/* 0x86 not used */ +#define E_TP_REF_OVERFLOW (TP_ERROR_MASK | 0x87) /* dr reference overflow */ +#define E_TP_NO_CR_ON_NC (TP_ERROR_MASK | 0x88) /* dr cr refused on this nc */ +/* 0x89 not used */ +#define E_TP_LENGTH_INVAL (TP_ERROR_MASK | 0x8a) /* dr inval length in hdr*/ + +/******************************************************************************/ +/* */ +/* */ +/* Connection Less Network Layer */ +/* */ +/* */ +/******************************************************************************/ + +#define E_CLNL_??? (CLNL_ERROR_MASK | 0x1) /* explanation */ + +/******************************************************************************/ +/* */ +/* */ +/* Connection Oriented Network Layer */ +/* */ +/* */ +/******************************************************************************/ + /* see p. 149 of ISO 8208 */ +#define E_CO_NOERROR (CONL_ERROR_MASK | 0x0) /* no add'l info */ +#define E_CO_INV_PS (CONL_ERROR_MASK | 0x1) /* invalid p(s) */ +#define E_CO_INV_PR (CONL_ERROR_MASK | 0x2) /* invalid p(r) */ + /* dot dot dot */ +#define E_CO_INV_PKT_TYPE (CONL_ERROR_MASK | 0x10) /* packet type invalid*/ +#define E_CO_INV_PKT_R1 (CONL_ERROR_MASK | 0x11) /* for state r1 */ +#define E_CO_INV_PKT_R2 (CONL_ERROR_MASK | 0x12) /* for state r2 */ +#define E_CO_INV_PKT_R3 (CONL_ERROR_MASK | 0x13) /* for state r3 */ +#define E_CO_INV_PKT_P1 (CONL_ERROR_MASK | 0x14) /* for state p1 */ +#define E_CO_INV_PKT_P2 (CONL_ERROR_MASK | 0x15) /* for state p2 */ +#define E_CO_INV_PKT_P3 (CONL_ERROR_MASK | 0x16) /* for state p3 */ +#define E_CO_INV_PKT_P4 (CONL_ERROR_MASK | 0x17) /* for state p4 */ +#define E_CO_INV_PKT_P5 (CONL_ERROR_MASK | 0x18) /* for state p5 */ +#define E_CO_INV_PKT_P6 (CONL_ERROR_MASK | 0x19) /* for state p6 */ +#define E_CO_INV_PKT_P7 (CONL_ERROR_MASK | 0x1a) /* for state p7 */ +#define E_CO_INV_PKT_D1 (CONL_ERROR_MASK | 0x1b) /* for state d1 */ +#define E_CO_INV_PKT_D2 (CONL_ERROR_MASK | 0x1c) /* for state d2 */ +#define E_CO_INV_PKT_D3 (CONL_ERROR_MASK | 0x1d) /* for state d3 */ + /* dot dot dot */ +#define E_CO_PKT_NOT_ALWD (CONL_ERROR_MASK | 0x20) /* packet not allowed */ +#define E_CO_PNA_UNIDENT (CONL_ERROR_MASK | 0x21) /* unidentifiable pkt */ +#define E_CO_PNA_ONEWAY (CONL_ERROR_MASK | 0x22) /* call on 1-way lc */ +#define E_CO_PNA_PVC (CONL_ERROR_MASK | 0x23) /* inv pkt type on a pvc */ +#define E_CO_PNA_UNASSLC (CONL_ERROR_MASK | 0x24) /* pkt on unassigned lc */ +#define E_CO_PNA_REJECT (CONL_ERROR_MASK | 0x25) /* REJ not subscribed to*/ +#define E_CO_PNA_SHORT (CONL_ERROR_MASK | 0x26) /* pkt too short */ +#define E_CO_PNA_LONG (CONL_ERROR_MASK | 0x27) /* pkt too long */ +#define E_CO_PNA_INVGFI (CONL_ERROR_MASK | 0x28) /* inv gen format id */ +#define E_CO_PNA_NZLCI (CONL_ERROR_MASK | 0x29) \ + /* restart or reg pkt with nonzero logical channel identifier */ +#define E_CO_PNA_FACIL (CONL_ERROR_MASK | 0x2a) \ + /* pkt type not compat with facility */ +#define E_CO_PNA_UINTCON (CONL_ERROR_MASK | 0x2b) /* unauthor intrpt conf */ +#define E_CO_PNA_UINTRPT (CONL_ERROR_MASK | 0x2c) /* unauthorized intrpt */ +#define E_CO_PNA_UREJECT (CONL_ERROR_MASK | 0x2d) /* unauthorized reject */ + +#define E_CO_TMR_EXP (CONL_ERROR_MASK | 0x30) /* timer expired */ +#define E_CO_TMR_CALR (CONL_ERROR_MASK | 0x31) /* inc. call or call req */ +#define E_CO_TMR_CLRI (CONL_ERROR_MASK | 0x32) /* clear indication */ +#define E_CO_TMR_RSTI (CONL_ERROR_MASK | 0x33) /* reset indication */ +#define E_CO_TMR_RRTI (CONL_ERROR_MASK | 0x34) /* restart indication */ + +#define E_CO_REG_PROB (CONL_ERROR_MASK | 0x40)\ + /* call setup, clear, or registration problem */ +#define E_CO_REG_CODE (CONL_ERROR_MASK | 0x41) /* code not allowed */ +#define E_CO_REG_PARM (CONL_ERROR_MASK | 0x42) /* parameter not allowed */ +#define E_CO_REG_ICDA (CONL_ERROR_MASK | 0x43) /* invalid called addr */ +#define E_CO_REG_ICGA (CONL_ERROR_MASK | 0x44) /* invalid calling addr */ +#define E_CO_REG_ILEN (CONL_ERROR_MASK | 0x45) /* invalid facil length */ +#define E_CO_REG_IBAR (CONL_ERROR_MASK | 0x46) /* incoming call barred */ +#define E_CO_REG_NOLC (CONL_ERROR_MASK | 0x47) /* no logical chan avail*/ +#define E_CO_REG_COLL (CONL_ERROR_MASK | 0x48) /* call collision */ +#define E_CO_REG_DUPF (CONL_ERROR_MASK | 0x49) /* dupl facil requested */ +#define E_CO_REG_NZAL (CONL_ERROR_MASK | 0x4a) /* non-zero addr length */ +#define E_CO_REG_NZFL (CONL_ERROR_MASK | 0x4b) /* non-zero facil length */ +#define E_CO_REG_EFNP (CONL_ERROR_MASK | 0x4c) \ + /* expected facil not provided */ +#define E_CO_REG_ICCITT (CONL_ERROR_MASK | 0x4d) \ + /* invalid CCITT-specified DTE facil */ + +#define E_CO_MISC (CONL_ERROR_MASK | 0x50) /* miscellaneous */ +#define E_CO_MISC_CAUSE (CONL_ERROR_MASK | 0x51) /* improper cause code */ +#define E_CO_MISC_ALIGN (CONL_ERROR_MASK | 0x52) /* not octet-aligned */ +#define E_CO_MISC_IQBS (CONL_ERROR_MASK | 0x53) \ + /* inconsistent Q bit settings */ + +#define E_CO_INTL (CONL_ERROR_MASK | 0x70) /* international problem */ +#define E_CO_IREMNWK (CONL_ERROR_MASK | 0x71) /* remote network problem */ +#define E_CO_INPROTO (CONL_ERROR_MASK | 0x72) /* int'l protocol problem */ +#define E_CO_ILINKDWN (CONL_ERROR_MASK | 0x73) /* int'l link down */ +#define E_CO_ILINKBSY (CONL_ERROR_MASK | 0x74) /* int'l link busy */ +#define E_CO_IXNETFAC (CONL_ERROR_MASK | 0x75) /* transit netwk facil */ +#define E_CO_IRNETFAC (CONL_ERROR_MASK | 0x76) /* remote netwk facil */ +#define E_CO_IROUTING (CONL_ERROR_MASK | 0x77) /* int'l routing prob */ +#define E_CO_ITMPRTG (CONL_ERROR_MASK | 0x78) /* temporary routing prob */ +#define E_CO_IUNKDNIC (CONL_ERROR_MASK | 0x79) /* unknown called DNIC */ +#define E_CO_IMAINT (CONL_ERROR_MASK | 0x7a) /* maintenance action */ + +#define E_CO_TIMO (CONL_ERROR_MASK | 0x90) \ + /* timer expired or retransmission count surpassed */ +#define E_CO_TIM_INTRP (CONL_ERROR_MASK | 0x91) /* for interrupt */ +#define E_CO_TIM_DATA (CONL_ERROR_MASK | 0x92) /* for data */ +#define E_CO_TIM_REJ (CONL_ERROR_MASK | 0x93) /* for reject */ + +#define E_CO_DTE_SPEC (CONL_ERROR_MASK | 0xa0) /* DTE-specific */ +#define E_CO_DTE_OK (CONL_ERROR_MASK | 0xa1) /* DTE operational */ +#define E_CO_DTE_NOK (CONL_ERROR_MASK | 0xa2) /* DTE not operational */ +#define E_CO_DTE_RSRC (CONL_ERROR_MASK | 0xa3) /* DTE resource constraint*/ +#define E_CO_DTE_FSLCT (CONL_ERROR_MASK | 0xa4) /* fast select not subsc */ +#define E_CO_DTE_PFPKT (CONL_ERROR_MASK | 0xa5) /* partially full pkt */ +#define E_CO_DTE_DBIT (CONL_ERROR_MASK | 0xa6) /* D-bit proc not supp */ +#define E_CO_DTE_RCCON (CONL_ERROR_MASK | 0xa7) /* reg/canell confirmed */ + +#define E_CO_OSI_NSP (CONL_ERROR_MASK | 0xe0) /* OSI net svc problem */ +#define E_CO_OSI_DISCT (CONL_ERROR_MASK | 0xe1) /* disconnect transient */ +#define E_CO_OSI_DISCP (CONL_ERROR_MASK | 0xe2) /* disconnect permanent */ +#define E_CO_OSI_REJT (CONL_ERROR_MASK | 0xe3) /* reject transient */ +#define E_CO_OSI_REJP (CONL_ERROR_MASK | 0xe4) /* reject permanent */ +#define E_CO_OSI_QOST (CONL_ERROR_MASK | 0xe5) /* reject QOS transient */ +#define E_CO_OSI_QOSP (CONL_ERROR_MASK | 0xe6) /* reject QOS permanent */ +#define E_CO_OSI_NSAPT (CONL_ERROR_MASK | 0xe7) /* NSAP unreach transient */ +#define E_CO_OSI_NSAPP (CONL_ERROR_MASK | 0xe8) /* NSAP unreach permanent */ +#define E_CO_OSI_RESET (CONL_ERROR_MASK | 0xe9) /* reset no reason */ +#define E_CO_OSI_CONGEST (CONL_ERROR_MASK | 0xea) /* reset congestion */ +#define E_CO_OSI_UNSAP (CONL_ERROR_MASK | 0xeb) /* unknown NSAP permanent */ + +#define E_CO_HLI_INIT (CONL_ERROR_MASK | 0xf0) /* higher level initiated*/ +#define E_CO_HLI_DISCN (CONL_ERROR_MASK | 0xf1) /* disconnect normal */ +#define E_CO_HLI_DISCA (CONL_ERROR_MASK | 0xf2) /* disconnect abnormal */ +#define E_CO_HLI_DISCI (CONL_ERROR_MASK | 0xf3) /* disconnect incompatible*/ +#define E_CO_HLI_REJT (CONL_ERROR_MASK | 0xf4) /* reject transient */ +#define E_CO_HLI_REJP (CONL_ERROR_MASK | 0xf5) /* reject permanent */ +#define E_CO_HLI_QOST (CONL_ERROR_MASK | 0xf6) /* reject QOS transient */ +#define E_CO_HLI_QOSP (CONL_ERROR_MASK | 0xf7) /* reject QOS permanent */ +#define E_CO_HLI_REJI (CONL_ERROR_MASK | 0xf8) /* reject incompatible */ +#define E_CO_HLI_PROTOID (CONL_ERROR_MASK | 0xf9) /* unrecog proto id */ +#define E_CO_HLI_RESYNC (CONL_ERROR_MASK | 0xfa) /* reset - user resync */ + +/* Cause on 8208 CLEAR field */ +#define E_CO_NUMBERBUSY (CONL_ERROR_MASK | 0x101) /* Number busy */ +#define E_CO_INVFACREQ (CONL_ERROR_MASK | 0x103) /* invalid facil req */ +#define E_CO_NETCONGEST (CONL_ERROR_MASK | 0x105) /* Network congestion */ +#define E_CO_OUTOFORDER (CONL_ERROR_MASK | 0x109) /* Out of order */ +#define E_CO_ACCESSBAR (CONL_ERROR_MASK | 0x10b) /* access barred */ +#define E_CO_NOTOBTAIN (CONL_ERROR_MASK | 0x10d) /* not obtainable */ +#define E_CO_REMPROCERR (CONL_ERROR_MASK | 0x111) /* Remote procedure err */ +#define E_CO_LOCPROCERR (CONL_ERROR_MASK | 0x113) /* Local procedure err */ +#define E_CO_RPOAOOO (CONL_ERROR_MASK | 0x115) /* RPOA out of order */ +#define E_CO_NOREVCHG (CONL_ERROR_MASK | 0x119) /* Revs chg not accepted*/ +#define E_CO_INCOMPAT (CONL_ERROR_MASK | 0x121) /* Incompatible dest */ +#define E_CO_NOFASTSEL (CONL_ERROR_MASK | 0x129) + /* Fast select accpt not subscribed */ +#define E_CO_NOSHIP (CONL_ERROR_MASK | 0x139) /* ship absent */ +#define E_CO_GWPROCERR (CONL_ERROR_MASK | 0x1c1) /* Gateway-detected err*/ +#define E_CO_GWCONGEST (CONL_ERROR_MASK | 0x1c3) /* Gateway congestion*/ + +/* ARGO only */ +#define E_CO_QFULL (CONL_ERROR_MASK | 0x100) /* dropped packet - queue full*/ +#define E_CO_AIWP (CONL_ERROR_MASK | 0x102) /* addr incompat w/proto */ +#define E_CO_CHAN (CONL_ERROR_MASK | 0x104) /* bad channel number */ + +/* ARGO only; driver specific */ +#define E_CO_NORESOURCES (CONL_ERROR_MASK | 0x1b0) /* eicon clogged */ +#define E_CO_PDNDOWN (CONL_ERROR_MASK | 0x1b1) /* physical net down */ +#define E_CO_DRVRCLRESET (CONL_ERROR_MASK | 0x1b2) /* driver clear/reset */ +#define E_CO_PDNCLRESET (CONL_ERROR_MASK | 0x1b3) /* PDN clear/reset */ +#define E_CO_DTECLRESET (CONL_ERROR_MASK | 0x1b4) /* board clear/reset */ +#define E_CO_UNKCLRESET (CONL_ERROR_MASK | 0x1b5) /* unexpected clr/rst */ + +#define CONL_ERROR_MAX 0x1c3 + +#endif /* __ISO_ERRNO__ */ diff --git a/sys/netiso/iso_pcb.c b/sys/netiso/iso_pcb.c new file mode 100644 index 0000000..0b50c60 --- /dev/null +++ b/sys/netiso/iso_pcb.c @@ -0,0 +1,617 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_pcb.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/iso_pcb.c,v $ + * + * Iso address family net-layer(s) pcb stuff. NEH 1/29/87 + */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> + +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netinet/in_systm.h> +#include <net/if.h> +#include <net/route.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> +#include <sys/protosw.h> + +#ifdef TPCONS +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> +#endif + +#define PCBNULL (struct isopcb *)0 +struct iso_addr zeroiso_addr = { + 0 +}; + + +/* + * FUNCTION: iso_pcballoc + * + * PURPOSE: creates an isopcb structure in an mbuf, + * with socket (so), and + * puts it in the queue with head (head) + * + * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf + */ +int +iso_pcballoc(so, head) + struct socket *so; + struct isopcb *head; +{ + register struct isopcb *isop; + + IFDEBUG(D_ISO) + printf("iso_pcballoc(so 0x%x)\n", so); + ENDDEBUG + MALLOC(isop, struct isopcb *, sizeof(*isop), M_PCB, M_NOWAIT); + if (isop == NULL) + return ENOBUFS; + bzero((caddr_t)isop, sizeof(*isop)); + isop->isop_head = head; + isop->isop_socket = so; + insque(isop, head); + if (so) + so->so_pcb = (caddr_t)isop; + return 0; +} + +/* + * FUNCTION: iso_pcbbind + * + * PURPOSE: binds the address given in *(nam) to the socket + * specified by the isopcb in *(isop) + * If the given address is zero, it makes sure the + * address isn't already in use and if it's got a network + * portion, we look for an interface with that network + * address. If the address given is zero, we allocate + * a port and stuff it in the (nam) structure. + * + * RETURNS: errno E* or 0 if ok. + * + * SIDE EFFECTS: increments head->isop_lport if it allocates a port # + * + * NOTES: + */ +#define satosiso(sa) ((struct sockaddr_iso *)(sa)) +int +iso_pcbbind(isop, nam) + register struct isopcb *isop; + struct mbuf *nam; +{ + register struct isopcb *head = isop->isop_head; + register struct sockaddr_iso *siso; + struct iso_ifaddr *ia; + union { + char data[2]; + u_short s; + } suf; + + IFDEBUG(D_ISO) + printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam); + ENDDEBUG + suf.s = 0; + if (iso_ifaddr == 0) /* any interfaces attached? */ + return EADDRNOTAVAIL; + if (isop->isop_laddr) /* already bound */ + return EADDRINUSE; + if(nam == (struct mbuf *)0) { + isop->isop_laddr = &isop->isop_sladdr; + isop->isop_sladdr.siso_len = sizeof(struct sockaddr_iso); + isop->isop_sladdr.siso_family = AF_ISO; + isop->isop_sladdr.siso_tlen = 2; + isop->isop_sladdr.siso_nlen = 0; + isop->isop_sladdr.siso_slen = 0; + isop->isop_sladdr.siso_plen = 0; + goto noname; + } + siso = mtod(nam, struct sockaddr_iso *); + IFDEBUG(D_ISO) + printf("iso_pcbbind(name len 0x%x)\n", nam->m_len); + printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr)); + ENDDEBUG + /* + * We would like sort of length check but since some OSI addrs + * do not have fixed length, we can't really do much. + * The ONLY thing we can say is that an osi addr has to have + * at LEAST an afi and one more byte and had better fit into + * a struct iso_addr. + * However, in fact the size of the whole thing is a struct + * sockaddr_iso, so probably this is what we should check for. + */ + if( (nam->m_len < 2) || (nam->m_len < siso->siso_len)) { + return ENAMETOOLONG; + } + if (siso->siso_nlen) { + /* non-zero net addr- better match one of our interfaces */ + IFDEBUG(D_ISO) + printf("iso_pcbbind: bind to NOT zeroisoaddr\n"); + ENDDEBUG + for (ia = iso_ifaddr; ia; ia = ia->ia_next) + if (SAME_ISOADDR(siso, &ia->ia_addr)) + break; + if (ia == 0) + return EADDRNOTAVAIL; + } + if (siso->siso_len <= sizeof (isop->isop_sladdr)) { + isop->isop_laddr = &isop->isop_sladdr; + } else { + if ((nam = m_copy(nam, 0, (int)M_COPYALL)) == 0) + return ENOBUFS; + isop->isop_laddr = mtod(nam, struct sockaddr_iso *); + } + bcopy((caddr_t)siso, (caddr_t)isop->isop_laddr, siso->siso_len); + if (siso->siso_tlen == 0) + goto noname; + if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 && + iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)) + return EADDRINUSE; + if (siso->siso_tlen <= 2) { + bcopy(TSEL(siso), suf.data, sizeof(suf.data)); + suf.s = ntohs(suf.s); + if((suf.s < ISO_PORT_RESERVED) && + (isop->isop_socket->so_state && SS_PRIV) == 0) + return EACCES; + } else { + register char *cp; +noname: + cp = TSEL(isop->isop_laddr); + IFDEBUG(D_ISO) + printf("iso_pcbbind noname\n"); + ENDDEBUG + do { + if (head->isop_lport++ < ISO_PORT_RESERVED || + head->isop_lport > ISO_PORT_USERRESERVED) + head->isop_lport = ISO_PORT_RESERVED; + suf.s = htons(head->isop_lport); + cp[0] = suf.data[0]; + cp[1] = suf.data[1]; + } while (iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr)); + } + IFDEBUG(D_ISO) + printf("iso_pcbbind returns 0, suf 0x%x\n", suf); + ENDDEBUG + return 0; +} +/* + * FUNCTION: iso_pcbconnect + * + * PURPOSE: Make the isopcb (isop) look like it's connected. + * In other words, give it the peer address given in + * the mbuf * (nam). Make sure such a combination + * of local, peer addresses doesn't already exist + * for this protocol. Internet mentality prevails here, + * wherein a src,dst pair uniquely identifies a connection. + * Both net address and port must be specified in argument + * (nam). + * If we don't have a local address for this socket yet, + * we pick one by calling iso_pcbbind(). + * + * RETURNS: errno E* or 0 if ok. + * + * SIDE EFFECTS: Looks up a route, which may cause one to be left + * in the isopcb. + * + * NOTES: + */ +int +iso_pcbconnect(isop, nam) + register struct isopcb *isop; + struct mbuf *nam; +{ + register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *); + int local_zero, error = 0; + struct iso_ifaddr *ia; + + IFDEBUG(D_ISO) + printf("iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x", + isop, isop->isop_socket, nam); + printf("nam->m_len 0x%x), addr:\n", nam->m_len); + dump_isoaddr(siso); + ENDDEBUG + if (nam->m_len < siso->siso_len) + return EINVAL; + if (siso->siso_family != AF_ISO) + return EAFNOSUPPORT; + if (siso->siso_nlen == 0) { + if (ia = iso_ifaddr) { + int nlen = ia->ia_addr.siso_nlen; + ovbcopy(TSEL(siso), nlen + TSEL(siso), + siso->siso_plen + siso->siso_tlen + siso->siso_slen); + bcopy((caddr_t)&ia->ia_addr.siso_addr, + (caddr_t)&siso->siso_addr, nlen + 1); + /* includes siso->siso_nlen = nlen; */ + } else + return EADDRNOTAVAIL; + } + /* + * Local zero means either not bound, or bound to a TSEL, but no + * particular local interface. So, if we want to send somebody + * we need to choose a return address. + */ + local_zero = + ((isop->isop_laddr == 0) || (isop->isop_laddr->siso_nlen == 0)); + if (local_zero) { + int flags; + + IFDEBUG(D_ISO) + printf("iso_pcbconnect localzero 1\n"); + ENDDEBUG + /* + * If route is known or can be allocated now, + * our src addr is taken from the i/f, else punt. + */ + flags = isop->isop_socket->so_options & SO_DONTROUTE; + if (error = clnp_route(&siso->siso_addr, &isop->isop_route, flags, + (struct sockaddr **)0, &ia)) + return error; + IFDEBUG(D_ISO) + printf("iso_pcbconnect localzero 2, ro->ro_rt 0x%x", + isop->isop_route.ro_rt); + printf(" ia 0x%x\n", ia); + ENDDEBUG + } + IFDEBUG(D_ISO) + printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n", + isop, isop->isop_socket); + ENDDEBUG + if (local_zero) { + int nlen, tlen, totlen; caddr_t oldtsel, newtsel; + siso = isop->isop_laddr; + if (siso == 0 || siso->siso_tlen == 0) + (void)iso_pcbbind(isop, (struct mbuf *)0); + /* + * Here we have problem of squezeing in a definite network address + * into an existing sockaddr_iso, which in fact may not have room + * for it. This gets messy. + */ + siso = isop->isop_laddr; + oldtsel = TSEL(siso); + tlen = siso->siso_tlen; + nlen = ia->ia_addr.siso_nlen; + totlen = tlen + nlen + _offsetof(struct sockaddr_iso, siso_data[0]); + if ((siso == &isop->isop_sladdr) && + (totlen > sizeof(isop->isop_sladdr))) { + struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); + if (m == 0) + return ENOBUFS; + m->m_len = totlen; + isop->isop_laddr = siso = mtod(m, struct sockaddr_iso *); + } + siso->siso_nlen = ia->ia_addr.siso_nlen; + newtsel = TSEL(siso); + ovbcopy(oldtsel, newtsel, tlen); + bcopy(ia->ia_addr.siso_data, siso->siso_data, nlen); + siso->siso_tlen = tlen; + siso->siso_family = AF_ISO; + siso->siso_len = totlen; + siso = mtod(nam, struct sockaddr_iso *); + } + IFDEBUG(D_ISO) + printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n", + isop, isop->isop_socket); + ENDDEBUG + /* + * If we had to allocate space to a previous big foreign address, + * and for some reason we didn't free it, we reuse it knowing + * that is going to be big enough, as sockaddrs are delivered in + * 128 byte mbufs. + * If the foreign address is small enough, we use default space; + * otherwise, we grab an mbuf to copy into. + */ + if (isop->isop_faddr == 0 || isop->isop_faddr == &isop->isop_sfaddr) { + if (siso->siso_len <= sizeof(isop->isop_sfaddr)) + isop->isop_faddr = &isop->isop_sfaddr; + else { + struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT); + if (m == 0) + return ENOBUFS; + isop->isop_faddr = mtod(m, struct sockaddr_iso *); + } + } + bcopy((caddr_t)siso, (caddr_t)isop->isop_faddr, siso->siso_len); + IFDEBUG(D_ISO) + printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n", + isop, isop->isop_socket); + printf("iso_pcbconnect connected to addr:\n"); + dump_isoaddr(isop->isop_faddr); + printf("iso_pcbconnect end: src addr:\n"); + dump_isoaddr(isop->isop_laddr); + ENDDEBUG + return 0; +} + +/* + * FUNCTION: iso_pcbdisconnect() + * + * PURPOSE: washes away the peer address info so the socket + * appears to be disconnected. + * If there's no file descriptor associated with the socket + * it detaches the pcb. + * + * RETURNS: Nada. + * + * SIDE EFFECTS: May detach the pcb. + * + * NOTES: + */ +void +iso_pcbdisconnect(isop) + struct isopcb *isop; +{ + void iso_pcbdetach(); + register struct sockaddr_iso *siso; + + IFDEBUG(D_ISO) + printf("iso_pcbdisconnect(isop 0x%x)\n", isop); + ENDDEBUG + /* + * Preserver binding infnormation if already bound. + */ + if ((siso = isop->isop_laddr) && siso->siso_nlen && siso->siso_tlen) { + caddr_t otsel = TSEL(siso); + siso->siso_nlen = 0; + ovbcopy(otsel, TSEL(siso), siso->siso_tlen); + } + if (isop->isop_faddr && isop->isop_faddr != &isop->isop_sfaddr) + m_freem(dtom(isop->isop_faddr)); + isop->isop_faddr = 0; + if (isop->isop_socket->so_state & SS_NOFDREF) + iso_pcbdetach(isop); +} + +/* + * FUNCTION: iso_pcbdetach + * + * PURPOSE: detach the pcb at *(isop) from it's socket and free + * the mbufs associated with the pcb.. + * Dequeues (isop) from its head. + * + * RETURNS: Nada. + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +iso_pcbdetach(isop) + struct isopcb *isop; +{ + struct socket *so = isop->isop_socket; + + IFDEBUG(D_ISO) + printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n", + isop, isop->isop_socket, so); + ENDDEBUG +#ifdef TPCONS + if (isop->isop_chan) { + register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; + if (--isop->isop_refcnt > 0) + return; + if (lcp && lcp->lcd_state == DATA_TRANSFER) { + lcp->lcd_upper = 0; + lcp->lcd_upnext = 0; + pk_disconnect(lcp); + } + isop->isop_chan = 0; + } +#endif + if (so) { /* in the x.25 domain, we sometimes have no socket */ + so->so_pcb = 0; + sofree(so); + } + IFDEBUG(D_ISO) + printf("iso_pcbdetach 2 \n"); + ENDDEBUG + if (isop->isop_options) + (void)m_free(isop->isop_options); + IFDEBUG(D_ISO) + printf("iso_pcbdetach 3 \n"); + ENDDEBUG + if (isop->isop_route.ro_rt) + rtfree(isop->isop_route.ro_rt); + IFDEBUG(D_ISO) + printf("iso_pcbdetach 3.1\n"); + ENDDEBUG + if (isop->isop_clnpcache != NULL) { + struct clnp_cache *clcp = + mtod(isop->isop_clnpcache, struct clnp_cache *); + IFDEBUG(D_ISO) + printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n", + clcp, clcp->clc_hdr); + ENDDEBUG + if (clcp->clc_hdr != NULL) + m_free(clcp->clc_hdr); + IFDEBUG(D_ISO) + printf("iso_pcbdetach 3.3: freeing cache x%x\n", + isop->isop_clnpcache); + ENDDEBUG + m_free(isop->isop_clnpcache); + } + IFDEBUG(D_ISO) + printf("iso_pcbdetach 4 \n"); + ENDDEBUG + remque(isop); + IFDEBUG(D_ISO) + printf("iso_pcbdetach 5 \n"); + ENDDEBUG + if (isop->isop_laddr && (isop->isop_laddr != &isop->isop_sladdr)) + m_freem(dtom(isop->isop_laddr)); + free((caddr_t)isop, M_PCB); +} + + +/* + * FUNCTION: iso_pcbnotify + * + * PURPOSE: notify all connections in this protocol's queue (head) + * that have peer address (dst) of the problem (errno) + * by calling (notify) on the connections' isopcbs. + * + * RETURNS: Rien. + * + * SIDE EFFECTS: + * + * NOTES: (notify) is called at splimp! + */ +void +iso_pcbnotify(head, siso, errno, notify) + struct isopcb *head; + register struct sockaddr_iso *siso; + int errno, (*notify)(); +{ + register struct isopcb *isop; + int s = splimp(); + + IFDEBUG(D_ISO) + printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify); + ENDDEBUG + for (isop = head->isop_next; isop != head; isop = isop->isop_next) { + if (isop->isop_socket == 0 || isop->isop_faddr == 0 || + !SAME_ISOADDR(siso, isop->isop_faddr)) { + IFDEBUG(D_ISO) + printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" , + isop, isop->isop_socket); + printf("addrmatch cmp'd with (0x%x):\n", isop->isop_faddr); + dump_isoaddr(isop->isop_faddr); + ENDDEBUG + continue; + } + if (errno) + isop->isop_socket->so_error = errno; + if (notify) + (*notify)(isop); + } + splx(s); + IFDEBUG(D_ISO) + printf("END OF iso_pcbnotify\n" ); + ENDDEBUG +} + + +/* + * FUNCTION: iso_pcblookup + * + * PURPOSE: looks for a given combination of (faddr), (fport), + * (lport), (laddr) in the queue named by (head). + * Argument (flags) is ignored. + * + * RETURNS: ptr to the isopcb if it finds a connection matching + * these arguments, o.w. returns zero. + * + * SIDE EFFECTS: + * + * NOTES: + */ +struct isopcb * +iso_pcblookup(head, fportlen, fport, laddr) + struct isopcb *head; + register struct sockaddr_iso *laddr; + caddr_t fport; + int fportlen; +{ + register struct isopcb *isop; + register caddr_t lp = TSEL(laddr); + unsigned int llen = laddr->siso_tlen; + + IFDEBUG(D_ISO) + printf("iso_pcblookup(head 0x%x laddr 0x%x fport 0x%x)\n", + head, laddr, fport); + ENDDEBUG + for (isop = head->isop_next; isop != head; isop = isop->isop_next) { + if (isop->isop_laddr == 0 || isop->isop_laddr == laddr) + continue; + if (isop->isop_laddr->siso_tlen != llen) + continue; + if (bcmp(lp, TSEL(isop->isop_laddr), llen)) + continue; + if (fportlen && isop->isop_faddr && + bcmp(fport, TSEL(isop->isop_faddr), (unsigned)fportlen)) + continue; + /* PHASE2 + * addrmatch1 should be iso_addrmatch(a, b, mask) + * where mask is taken from isop->isop_laddrmask (new field) + * isop_lnetmask will also be available in isop + if (laddr != &zeroiso_addr && + !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr))) + continue; + */ + if (laddr->siso_nlen && (!SAME_ISOADDR(laddr, isop->isop_laddr))) + continue; + return (isop); + } + return (struct isopcb *)0; +} +#endif /* ISO */ diff --git a/sys/netiso/iso_pcb.h b/sys/netiso/iso_pcb.h new file mode 100644 index 0000000..aad76bc --- /dev/null +++ b/sys/netiso/iso_pcb.h @@ -0,0 +1,113 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_pcb.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: iso_pcb.h,v 4.3 88/06/29 15:00:01 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/iso_pcb.h,v $ */ + +#define MAXX25CRUDLEN 16 /* 16 bytes of call request user data */ + +/* + * Common structure pcb for argo protocol implementation. + */ +struct isopcb { + struct isopcb *isop_next,*isop_prev; /* pointers to other pcb's */ + struct isopcb *isop_head; /* pointer back to chain of pcbs for + this protocol */ + struct socket *isop_socket; /* back pointer to socket */ + struct sockaddr_iso *isop_laddr; + struct sockaddr_iso *isop_faddr; + struct route_iso { + struct rtentry *ro_rt; + struct sockaddr_iso ro_dst; + } isop_route; /* CLNP routing entry */ + struct mbuf *isop_options; /* CLNP options */ + struct mbuf *isop_optindex; /* CLNP options index */ + struct mbuf *isop_clnpcache; /* CLNP cached hdr */ + caddr_t isop_chan; /* actually struct pklcb * */ + u_short isop_refcnt; /* mult TP4 tpcb's -> here */ + u_short isop_lport; /* MISLEADLING work var */ + u_short isop_tuba_cached; /* for tuba address ref cnts */ + int isop_x25crud_len; /* x25 call request ud */ + char isop_x25crud[MAXX25CRUDLEN]; + struct ifaddr *isop_ifa; /* ESIS interface assoc w/sock */ + struct sockaddr_iso isop_sladdr, /* preallocated laddr */ + isop_sfaddr; /* preallocated faddr */ +}; + +#ifdef sotorawcb +/* + * Common structure pcb for raw clnp protocol access. + * Here are clnp specific extensions to the raw control block, + * and space is allocated to the necessary sockaddrs. + */ +struct rawisopcb { + struct rawcb risop_rcb; /* common control block prefix */ + int risop_flags; /* flags, e.g. raw sockopts */ + struct isopcb risop_isop; /* space for bound addresses, routes etc.*/ +}; +#endif + +#define sotoisopcb(so) ((struct isopcb *)(so)->so_pcb) +#define sotorawisopcb(so) ((struct rawisopcb *)(so)->so_pcb) + +#ifdef KERNEL +struct isopcb *iso_pcblookup(); +#endif diff --git a/sys/netiso/iso_proto.c b/sys/netiso/iso_proto.c new file mode 100644 index 0000000..59575c7 --- /dev/null +++ b/sys/netiso/iso_proto.c @@ -0,0 +1,197 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_proto.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: iso_proto.c,v 4.4 88/09/08 08:38:42 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/iso_proto.c,v $ + * + * iso_proto.c : protocol switch tables in the ISO domain + * + * ISO protocol family includes TP, CLTP, CLNP, 8208 + * TP and CLNP are implemented here. + */ + +#ifdef ISO +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/protosw.h> +#include <sys/domain.h> +#include <sys/mbuf.h> + +#include <net/radix.h> + +#include <netiso/iso.h> + +int clnp_output(), clnp_init(),clnp_slowtimo(),clnp_drain(); +int rclnp_input(), rclnp_output(), rclnp_ctloutput(), raw_usrreq(); +int clnp_usrreq(); + +int tp_ctloutput(), tpclnp_ctlinput(), tpclnp_input(), tp_usrreq(); +int tp_init(), tp_fasttimo(), tp_slowtimo(), tp_drain(); +int cons_init(), tpcons_input(); + +int isis_input(); +int esis_input(), esis_ctlinput(), esis_init(), esis_usrreq(); +int idrp_input(), idrp_init(), idrp_usrreq(); +int cltp_input(), cltp_ctlinput(), cltp_init(), cltp_usrreq(), cltp_output(); + +#ifdef TUBA +int tuba_usrreq(), tuba_ctloutput(), tuba_init(), tuba_tcpinput(); +int tuba_slowtimo(), tuba_fasttimo(); +#endif + +struct protosw isosw[] = { +/* + * We need a datagram entry through which net mgmt programs can get + * to the iso_control procedure (iso ioctls). Thus, a minimal + * SOCK_DGRAM interface is provided here. + * THIS ONE MUST BE FIRST: Kludge city : socket() says if(!proto) call + * pffindtype, which gets the first entry that matches the type. + * sigh. + */ +{ SOCK_DGRAM, &isodomain, ISOPROTO_CLTP, PR_ATOMIC|PR_ADDR, + 0, cltp_output, 0, 0, + cltp_usrreq, + cltp_init, 0, 0, 0 +}, + +/* + * A datagram interface for clnp cannot co-exist with TP/CLNP + * because CLNP has no way to discriminate incoming TP packets from + * packets coming in for any other higher layer protocol. + * Old way: set it up so that pffindproto(... dgm, clnp) fails. + * New way: let pffindproto work (for x.25, thank you) but create + * a clnp_usrreq() that returns error on PRU_ATTACH. + */ +{SOCK_DGRAM, &isodomain, ISOPROTO_CLNP, 0, + 0, clnp_output, 0, 0, + clnp_usrreq, + clnp_init, 0, clnp_slowtimo, clnp_drain, +}, + +/* raw clnp */ +{ SOCK_RAW, &isodomain, ISOPROTO_RAW, PR_ATOMIC|PR_ADDR, + rclnp_input, rclnp_output, 0, rclnp_ctloutput, + clnp_usrreq, + 0, 0, 0, 0 +}, + +/* ES-IS protocol */ +{ SOCK_DGRAM, &isodomain, ISOPROTO_ESIS, PR_ATOMIC|PR_ADDR, + esis_input, 0, esis_ctlinput, 0, + esis_usrreq, + esis_init, 0, 0, 0 +}, + +/* ISOPROTO_INTRAISIS */ +{ SOCK_DGRAM, &isodomain, ISOPROTO_INTRAISIS, PR_ATOMIC|PR_ADDR, + isis_input, 0, 0, 0, + esis_usrreq, + 0, 0, 0, 0 +}, + +/* ISOPROTO_IDRP */ +{ SOCK_DGRAM, &isodomain, ISOPROTO_IDRP, PR_ATOMIC|PR_ADDR, + idrp_input, 0, 0, 0, + idrp_usrreq, + idrp_init, 0, 0, 0 +}, + +/* ISOPROTO_TP */ +{ SOCK_SEQPACKET, &isodomain, ISOPROTO_TP, PR_CONNREQUIRED|PR_WANTRCVD, + tpclnp_input, 0, tpclnp_ctlinput, tp_ctloutput, + tp_usrreq, + tp_init, tp_fasttimo, tp_slowtimo, tp_drain, +}, + +#ifdef TUBA +{ SOCK_STREAM, &isodomain, ISOPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD, + tuba_tcpinput, 0, 0, tuba_ctloutput, + tuba_usrreq, + tuba_init, tuba_fasttimo, tuba_fasttimo, 0 +}, +#endif + +#ifdef TPCONS +/* ISOPROTO_TP */ +{ SOCK_SEQPACKET, &isodomain, ISOPROTO_TP0, PR_CONNREQUIRED|PR_WANTRCVD, + tpcons_input, 0, 0, tp_ctloutput, + tp_usrreq, + cons_init, 0, 0, 0, +}, +#endif + +}; + + +struct domain isodomain = { + AF_ISO, /* family */ + "iso-domain", /* name */ + 0, /* initialize routine */ + 0, /* externalize access rights */ + 0, /* dispose of internalized rights */ + isosw, /* protosw */ + &isosw[sizeof(isosw)/sizeof(isosw[0])], /* NPROTOSW */ + 0, /* next */ + rn_inithead, /* rtattach */ + 48, /* rtoffset */ + sizeof(struct sockaddr_iso) /* maxkeylen */ +}; +#endif /* ISO */ diff --git a/sys/netiso/iso_snpac.c b/sys/netiso/iso_snpac.c new file mode 100644 index 0000000..2473ae7 --- /dev/null +++ b/sys/netiso/iso_snpac.c @@ -0,0 +1,736 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_snpac.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: iso_snpac.c,v 1.8 88/09/19 13:51:36 hagens Exp $ */ +/* $Source: /usr/argo/sys/netiso/RCS/iso_snpac.c,v $ */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/syslog.h> + +#include <net/if.h> +#include <net/if_dl.h> +#include <net/route.h> + +#include <netiso/iso.h> +#include <netiso/iso_var.h> +#include <netiso/iso_snpac.h> +#include <netiso/clnp.h> +#include <netiso/clnp_stat.h> +#include <netiso/esis.h> +#include <netiso/argo_debug.h> + +int iso_systype = SNPA_ES; /* default to be an ES */ +extern short esis_holding_time, esis_config_time, esis_esconfig_time; +extern struct timeval time; +extern void esis_config(); +extern int hz; +static void snpac_fixdstandmask(); + +struct sockaddr_iso blank_siso = {sizeof(blank_siso), AF_ISO}; +extern u_long iso_hashchar(); +static struct sockaddr_iso + dst = {sizeof(dst), AF_ISO}, + gte = {sizeof(dst), AF_ISO}, + src = {sizeof(dst), AF_ISO}, + msk = {sizeof(dst), AF_ISO}, + zmk = {0}; +#define zsi blank_siso +#define zero_isoa zsi.siso_addr +#define zap_isoaddr(a, b) {Bzero(&a.siso_addr, sizeof(*r)); r = b; \ + Bcopy(r, &a.siso_addr, 1 + (r)->isoa_len);} +#define S(x) ((struct sockaddr *)&(x)) + +static struct sockaddr_dl blank_dl = {sizeof(blank_dl), AF_LINK}; +static struct sockaddr_dl gte_dl; +#define zap_linkaddr(a, b, c, i) \ + (*a = blank_dl, bcopy(b, a->sdl_data, a->sdl_alen = c), a->sdl_index = i) + +/* + * We only keep track of a single IS at a time. + */ +struct rtentry *known_is; + +/* + * Addresses taken from NBS agreements, December 1987. + * + * These addresses assume on-the-wire transmission of least significant + * bit first. This is the method used by 802.3. When these + * addresses are passed to the token ring driver, (802.5), they + * must be bit-swaped because 802.5 transmission order is MSb first. + * + * Furthermore, according to IBM Austin, these addresses are not + * true token ring multicast addresses. More work is necessary + * to get multicast to work right on token ring. + * + * Currently, the token ring driver does not handle multicast, so + * these addresses are converted into the broadcast address in + * lan_output() That means that if these multicast addresses change + * the token ring driver must be altered. + */ +char all_es_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x04 }; +char all_is_snpa[] = { 0x09, 0x00, 0x2b, 0x00, 0x00, 0x05 }; +char all_l1is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x14}; +char all_l2is_snpa[] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x15}; + +union sockunion { + struct sockaddr_iso siso; + struct sockaddr_dl sdl; + struct sockaddr sa; +}; + +/* + * FUNCTION: llc_rtrequest + * + * PURPOSE: Manage routing table entries specific to LLC for ISO. + * + * NOTES: This does a lot of obscure magic; + */ +llc_rtrequest(req, rt, sa) +int req; +register struct rtentry *rt; +struct sockaddr *sa; +{ + register union sockunion *gate = (union sockunion *)rt->rt_gateway; + register struct llinfo_llc *lc = (struct llinfo_llc *)rt->rt_llinfo, *lc2; + struct rtentry *rt2; + struct ifnet *ifp = rt->rt_ifp; + int addrlen = ifp->if_addrlen; +#define LLC_SIZE 3 /* XXXXXX do this right later */ + + IFDEBUG (D_SNPA) + printf("llc_rtrequest(%d, %x, %x)\n", req, rt, sa); + ENDDEBUG + if (rt->rt_flags & RTF_GATEWAY) + return; + else switch (req) { + case RTM_ADD: + /* + * Case 1: This route may come from a route to iface with mask + * or from a default route. + */ + if (rt->rt_flags & RTF_CLONING) { + iso_setmcasts(ifp, req); + rt_setgate(rt, rt_key(rt), &blank_dl); + return; + } + if (lc != 0) + return; /* happens on a route change */ + /* FALLTHROUGH */ + case RTM_RESOLVE: + /* + * Case 2: This route may come from cloning, or a manual route + * add with a LL address. + */ + if (gate->sdl.sdl_family != AF_LINK) { + log(LOG_DEBUG, "llc_rtrequest: got non-link non-gateway route\n"); + break; + } + R_Malloc(lc, struct llinfo_llc *, sizeof (*lc)); + rt->rt_llinfo = (caddr_t)lc; + if (lc == 0) { + log(LOG_DEBUG, "llc_rtrequest: malloc failed\n"); + break; + } + Bzero(lc, sizeof(*lc)); + lc->lc_rt = rt; + rt->rt_flags |= RTF_LLINFO; + insque(lc, &llinfo_llc); + if (gate->sdl.sdl_alen == sizeof(struct esis_req) + addrlen) { + gate->sdl.sdl_alen -= sizeof(struct esis_req); + bcopy(addrlen + LLADDR(&gate->sdl), + (caddr_t)&lc->lc_er, sizeof(lc->lc_er)); + } else if (gate->sdl.sdl_alen == addrlen) + lc->lc_flags = (SNPA_ES | SNPA_VALID | SNPA_PERM); + break; + case RTM_DELETE: + if (rt->rt_flags & RTF_CLONING) + iso_setmcasts(ifp, req); + if (lc == 0) + return; + remque(lc); + Free(lc); + rt->rt_llinfo = 0; + rt->rt_flags &= ~RTF_LLINFO; + break; + } + if (rt->rt_rmx.rmx_mtu == 0) { + rt->rt_rmx.rmx_mtu = rt->rt_ifp->if_mtu - LLC_SIZE; + } +} +/* + * FUNCTION: iso_setmcasts + * + * PURPOSE: Enable/Disable ESIS/ISIS multicast reception on interfaces. + * + * NOTES: This also does a lot of obscure magic; + */ +iso_setmcasts(ifp, req) + struct ifnet *ifp; + int req; +{ + static char *addrlist[] = + { all_es_snpa, all_is_snpa, all_l1is_snpa, all_l2is_snpa, 0}; + struct ifreq ifr; + register caddr_t *cpp; + int doreset = 0; + + bzero((caddr_t)&ifr, sizeof(ifr)); + for (cpp = (caddr_t *)addrlist; *cpp; cpp++) { + bcopy(*cpp, (caddr_t)ifr.ifr_addr.sa_data, 6); + if (req == RTM_ADD) + if (ether_addmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) + doreset++; + else + if (ether_delmulti(&ifr, (struct arpcom *)ifp) == ENETRESET) + doreset++; + } + if (doreset) { + if (ifp->if_reset) + (*ifp->if_reset)(ifp->if_unit); + else + printf("iso_setmcasts: %s%d needs reseting to receive iso mcasts\n", + ifp->if_name, ifp->if_unit); + } +} +/* + * FUNCTION: iso_snparesolve + * + * PURPOSE: Resolve an iso address into snpa address + * + * RETURNS: 0 if addr is resolved + * errno if addr is unknown + * + * SIDE EFFECTS: + * + * NOTES: Now that we have folded the snpa cache into the routing + * table, we know there is no snpa address known for this + * destination. If we know of a default IS, then the address + * of the IS is returned. If no IS is known, then return the + * multi-cast address for "all ES" for this interface. + * + * NB: the last case described above constitutes the + * query configuration function 9542, sec 6.5 + * A mechanism is needed to prevent this function from + * being invoked if the system is an IS. + */ +iso_snparesolve(ifp, dest, snpa, snpa_len) +struct ifnet *ifp; /* outgoing interface */ +struct sockaddr_iso *dest; /* destination */ +caddr_t snpa; /* RESULT: snpa to be used */ +int *snpa_len; /* RESULT: length of snpa */ +{ + struct llinfo_llc *sc; /* ptr to snpa table entry */ + caddr_t found_snpa; + int addrlen; + + /* + * This hack allows us to send esis packets that have the destination snpa + * addresss embedded in the destination nsap address + */ + if (dest->siso_data[0] == AFI_SNA) { + /* + * This is a subnetwork address. Return it immediately + */ + IFDEBUG(D_SNPA) + printf("iso_snparesolve: return SN address\n"); + ENDDEBUG + addrlen = dest->siso_nlen - 1; /* subtract size of AFI */ + found_snpa = (caddr_t) dest->siso_data + 1; + /* + * If we are an IS, we can't do much with the packet; + * Check if we know about an IS. + */ + } else if (iso_systype != SNPA_IS && known_is != 0 && + (sc = (struct llinfo_llc *)known_is->rt_llinfo) && + (sc->lc_flags & SNPA_VALID)) { + register struct sockaddr_dl *sdl = + (struct sockaddr_dl *)(known_is->rt_gateway); + found_snpa = LLADDR(sdl); + addrlen = sdl->sdl_alen; + } else if (ifp->if_flags & IFF_BROADCAST) { + /* + * no IS, no match. Return "all es" multicast address for this + * interface, as per Query Configuration Function (9542 sec 6.5) + * + * Note: there is a potential problem here. If the destination + * is on the subnet and it does not respond with a ESH, but + * does send back a TP CC, a connection could be established + * where we always transmit the CLNP packet to "all es" + */ + addrlen = ifp->if_addrlen; + found_snpa = (caddr_t)all_es_snpa; + } else + return (ENETUNREACH); + bcopy(found_snpa, snpa, *snpa_len = addrlen); + return (0); +} + + +/* + * FUNCTION: snpac_free + * + * PURPOSE: free an entry in the iso address map table + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: If there is a route entry associated with cache + * entry, then delete that as well + */ +snpac_free(lc) +register struct llinfo_llc *lc; /* entry to free */ +{ + register struct rtentry *rt = lc->lc_rt; + register struct iso_addr *r; + + if (known_is == rt) + known_is = 0; + if (rt && (rt->rt_flags & RTF_UP) && + (rt->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))) { + RTFREE(rt); + rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, rt_mask(rt), + rt->rt_flags, (struct rtentry **)0); + RTFREE(rt); + } +} + +/* + * FUNCTION: snpac_add + * + * PURPOSE: Add an entry to the snpa cache + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: If entry already exists, then update holding time. + */ +snpac_add(ifp, nsap, snpa, type, ht, nsellength) +struct ifnet *ifp; /* interface info is related to */ +struct iso_addr *nsap; /* nsap to add */ +caddr_t snpa; /* translation */ +char type; /* SNPA_IS or SNPA_ES */ +u_short ht; /* holding time (in seconds) */ +int nsellength; /* nsaps may differ only in trailing bytes */ +{ + register struct llinfo_llc *lc; + register struct rtentry *rt; + struct rtentry *mrt = 0; + register struct iso_addr *r; /* for zap_isoaddr macro */ + int snpalen = min(ifp->if_addrlen, MAX_SNPALEN); + int new_entry = 0, index = ifp->if_index, iftype = ifp->if_type; + + IFDEBUG(D_SNPA) + printf("snpac_add(%x, %x, %x, %x, %x, %x)\n", + ifp, nsap, snpa, type, ht, nsellength); + ENDDEBUG + zap_isoaddr(dst, nsap); + rt = rtalloc1(S(dst), 0); + IFDEBUG(D_SNPA) + printf("snpac_add: rtalloc1 returns %x\n", rt); + ENDDEBUG + if (rt == 0) { + struct sockaddr *netmask; + int flags; + add: + if (nsellength) { + netmask = S(msk); flags = RTF_UP; + snpac_fixdstandmask(nsellength); + } else { + netmask = 0; flags = RTF_UP | RTF_HOST; + } + new_entry = 1; + zap_linkaddr((>e_dl), snpa, snpalen, index); + gte_dl.sdl_type = iftype; + if (rtrequest(RTM_ADD, S(dst), S(gte_dl), netmask, flags, &mrt) || + mrt == 0) + return (0); + rt = mrt; + rt->rt_refcnt--; + } else { + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)rt->rt_gateway; + rt->rt_refcnt--; + if ((rt->rt_flags & RTF_LLINFO) == 0) + goto add; + if (nsellength && (rt->rt_flags & RTF_HOST)) { + if (rt->rt_refcnt == 0) { + rtrequest(RTM_DELETE, S(dst), (struct sockaddr *)0, + (struct sockaddr *)0, 0, (struct rtentry *)0); + rt = 0; + goto add; + } else { + static struct iso_addr nsap2; register char *cp; + nsap2 = *nsap; + cp = nsap2.isoa_genaddr + nsap->isoa_len - nsellength; + while (cp < (char *)(1 + &nsap2)) + *cp++ = 0; + (void) snpac_add(ifp, &nsap2, snpa, type, ht, nsellength); + } + } + if (sdl->sdl_family != AF_LINK || sdl->sdl_alen == 0) { + int old_sdl_len = sdl->sdl_len; + if (old_sdl_len < sizeof(*sdl)) { + log(LOG_DEBUG, "snpac_add: cant make room for lladdr\n"); + return (0); + } + zap_linkaddr(sdl, snpa, snpalen, index); + sdl->sdl_len = old_sdl_len; + sdl->sdl_type = iftype; + new_entry = 1; + } + } + if ((lc = (struct llinfo_llc *)rt->rt_llinfo) == 0) + panic("snpac_rtrequest"); + rt->rt_rmx.rmx_expire = ht + time.tv_sec; + lc->lc_flags = SNPA_VALID | type; + if ((type & SNPA_IS) && !(iso_systype & SNPA_IS)) + snpac_logdefis(rt); + return (new_entry); +} + +static void +snpac_fixdstandmask(nsellength) +{ + register char *cp = msk.siso_data, *cplim; + + cplim = cp + (dst.siso_nlen -= nsellength); + msk.siso_len = cplim - (char *)&msk; + msk.siso_nlen = 0; + while (cp < cplim) + *cp++ = -1; + while (cp < (char *)msk.siso_pad) + *cp++ = 0; + for (cp = dst.siso_data + dst.siso_nlen; cp < (char *)dst.siso_pad; ) + *cp++ = 0; +} + +/* + * FUNCTION: snpac_ioctl + * + * PURPOSE: Set/Get the system type and esis parameters + * + * RETURNS: 0 on success, or unix error code + * + * SIDE EFFECTS: + * + * NOTES: + */ +snpac_ioctl (so, cmd, data) +struct socket *so; +int cmd; /* ioctl to process */ +caddr_t data; /* data for the cmd */ +{ + register struct systype_req *rq = (struct systype_req *)data; + + IFDEBUG(D_IOCTL) + if (cmd == SIOCSSTYPE) + printf("snpac_ioctl: cmd set, type x%x, ht %d, ct %d\n", + rq->sr_type, rq->sr_holdt, rq->sr_configt); + else + printf("snpac_ioctl: cmd get\n"); + ENDDEBUG + + if (cmd == SIOCSSTYPE) { + if ((so->so_state & SS_PRIV) == 0) + return (EPERM); + if ((rq->sr_type & (SNPA_ES|SNPA_IS)) == (SNPA_ES|SNPA_IS)) + return(EINVAL); + if (rq->sr_type & SNPA_ES) { + iso_systype = SNPA_ES; + } else if (rq->sr_type & SNPA_IS) { + iso_systype = SNPA_IS; + } else { + return(EINVAL); + } + esis_holding_time = rq->sr_holdt; + esis_config_time = rq->sr_configt; + if (esis_esconfig_time != rq->sr_esconfigt) { + untimeout(esis_config, (caddr_t)0); + esis_esconfig_time = rq->sr_esconfigt; + esis_config(); + } + } else if (cmd == SIOCGSTYPE) { + rq->sr_type = iso_systype; + rq->sr_holdt = esis_holding_time; + rq->sr_configt = esis_config_time; + rq->sr_esconfigt = esis_esconfig_time; + } else { + return (EINVAL); + } + return (0); +} + +/* + * FUNCTION: snpac_logdefis + * + * PURPOSE: Mark the IS passed as the default IS + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +snpac_logdefis(sc) +register struct rtentry *sc; +{ + register struct iso_addr *r; + register struct sockaddr_dl *sdl = (struct sockaddr_dl *)sc->rt_gateway; + register struct rtentry *rt; + + if (known_is == sc || !(sc->rt_flags & RTF_HOST)) + return; + if (known_is) { + RTFREE(known_is); + } + known_is = sc; + sc->rt_refcnt++; + rt = rtalloc1((struct sockaddr *)&zsi, 0); + if (rt == 0) + rtrequest(RTM_ADD, S(zsi), rt_key(sc), S(zmk), + RTF_DYNAMIC|RTF_GATEWAY, 0); + else { + if ((rt->rt_flags & RTF_DYNAMIC) && + (rt->rt_flags & RTF_GATEWAY) && rt_mask(rt)->sa_len == 0) + rt_setgate(rt, rt_key(rt), rt_key(sc)); + } +} + +/* + * FUNCTION: snpac_age + * + * PURPOSE: Time out snpac entries + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: When encountering an entry for the first time, snpac_age + * may delete up to SNPAC_AGE too many seconds. Ie. + * if the entry is added a moment before snpac_age is + * called, the entry will immediately have SNPAC_AGE + * seconds taken off the holding time, even though + * it has only been held a brief moment. + * + * The proper way to do this is set an expiry timeval + * equal to current time + holding time. Then snpac_age + * would time out entries where expiry date is older + * than the current time. + */ +void +snpac_age() +{ + register struct llinfo_llc *lc, *nlc; + register struct rtentry *rt; + + timeout(snpac_age, (caddr_t)0, SNPAC_AGE * hz); + + for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = nlc) { + nlc = lc->lc_next; + if (lc->lc_flags & SNPA_VALID) { + rt = lc->lc_rt; + if (rt->rt_rmx.rmx_expire && rt->rt_rmx.rmx_expire < time.tv_sec) + snpac_free(lc); + } + } +} + +/* + * FUNCTION: snpac_ownmulti + * + * PURPOSE: Determine if the snpa address is a multicast address + * of the same type as the system. + * + * RETURNS: true or false + * + * SIDE EFFECTS: + * + * NOTES: Used by interface drivers when not in eavesdrop mode + * as interm kludge until + * real multicast addresses can be configured + */ +snpac_ownmulti(snpa, len) +caddr_t snpa; +u_int len; +{ + return (((iso_systype & SNPA_ES) && + (!bcmp(snpa, (caddr_t)all_es_snpa, len))) || + ((iso_systype & SNPA_IS) && + (!bcmp(snpa, (caddr_t)all_is_snpa, len)))); +} + +/* + * FUNCTION: snpac_flushifp + * + * PURPOSE: Flush entries associated with specific ifp + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +snpac_flushifp(ifp) +struct ifnet *ifp; +{ + register struct llinfo_llc *lc; + + for (lc = llinfo_llc.lc_next; lc != & llinfo_llc; lc = lc->lc_next) { + if (lc->lc_rt->rt_ifp == ifp && (lc->lc_flags & SNPA_VALID)) + snpac_free(lc); + } +} + +/* + * FUNCTION: snpac_rtrequest + * + * PURPOSE: Make a routing request + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: In the future, this should make a request of a user + * level routing daemon. + */ +snpac_rtrequest(req, host, gateway, netmask, flags, ret_nrt) +int req; +struct iso_addr *host; +struct iso_addr *gateway; +struct iso_addr *netmask; +short flags; +struct rtentry **ret_nrt; +{ + register struct iso_addr *r; + + IFDEBUG(D_SNPA) + printf("snpac_rtrequest: "); + if (req == RTM_ADD) + printf("add"); + else if (req == RTM_DELETE) + printf("delete"); + else + printf("unknown command"); + printf(" dst: %s\n", clnp_iso_addrp(host)); + printf("\tgateway: %s\n", clnp_iso_addrp(gateway)); + ENDDEBUG + + + zap_isoaddr(dst, host); + zap_isoaddr(gte, gateway); + if (netmask) { + zap_isoaddr(msk, netmask); + msk.siso_nlen = 0; + msk.siso_len = msk.siso_pad - (u_char *)&msk; + } + + rtrequest(req, S(dst), S(gte), (netmask ? S(msk) : (struct sockaddr *)0), + flags, ret_nrt); +} + +/* + * FUNCTION: snpac_addrt + * + * PURPOSE: Associate a routing entry with an snpac entry + * + * RETURNS: nothing + * + * SIDE EFFECTS: + * + * NOTES: If a cache entry exists for gateway, then + * make a routing entry (host, gateway) and associate + * with gateway. + * + * If a route already exists and is different, first delete + * it. + * + * This could be made more efficient by checking + * the existing route before adding a new one. + */ +snpac_addrt(ifp, host, gateway, netmask) +struct ifnet *ifp; +struct iso_addr *host, *gateway, *netmask; +{ + register struct iso_addr *r; + + zap_isoaddr(dst, host); + zap_isoaddr(gte, gateway); + if (netmask) { + zap_isoaddr(msk, netmask); + msk.siso_nlen = 0; + msk.siso_len = msk.siso_pad - (u_char *)&msk; + rtredirect(S(dst), S(gte), S(msk), RTF_DONE, S(gte), 0); + } else + rtredirect(S(dst), S(gte), (struct sockaddr *)0, + RTF_DONE | RTF_HOST, S(gte), 0); +} +#endif /* ISO */ diff --git a/sys/netiso/iso_snpac.h b/sys/netiso/iso_snpac.h new file mode 100644 index 0000000..105e8dd --- /dev/null +++ b/sys/netiso/iso_snpac.h @@ -0,0 +1,112 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_snpac.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ + +#define MAX_SNPALEN 8 /* curiously equal to sizeof x.121 ( + plus 1 for nibble len) addr */ +struct snpa_req { + struct iso_addr sr_isoa; /* nsap address */ + u_char sr_len; /* length of snpa */ + u_char sr_snpa[MAX_SNPALEN]; /* snpa associated + with nsap address */ + u_char sr_flags; /* true if entry is valid */ + u_short sr_ht; /* holding time */ +}; + +#define SNPA_VALID 0x01 +#define SNPA_ES 0x02 +#define SNPA_IS 0x04 +#define SNPA_PERM 0x10 + +struct systype_req { + short sr_holdt; /* holding timer */ + short sr_configt; /* configuration timer */ + short sr_esconfigt; /* suggested ES configuration timer */ + char sr_type; /* SNPA_ES or SNPA_IS */ +}; + +struct esis_req { + short er_ht; /* holding time */ + u_char er_flags; /* type and validity */ +}; +/* + * Space for this structure gets added onto the end of a route + * going to an ethernet or other 802.[45x] device. + */ + +struct llinfo_llc { + struct llinfo_llc *lc_next; /* keep all llc routes linked */ + struct llinfo_llc *lc_prev; /* keep all llc routes linked */ + struct rtentry *lc_rt; /* backpointer to route */ + struct esis_req lc_er; /* holding time, etc */ +#define lc_ht lc_er.er_ht +#define lc_flags lc_er.er_flags +}; + + +/* ISO arp IOCTL data structures */ + +#define SIOCSSTYPE _IOW('a', 39, struct systype_req) /* set system type */ +#define SIOCGSTYPE _IOR('a', 40, struct systype_req) /* get system type */ + +#ifdef KERNEL +struct llinfo_llc llinfo_llc; /* head for linked lists */ +#endif /* KERNEL */ diff --git a/sys/netiso/iso_var.h b/sys/netiso/iso_var.h new file mode 100644 index 0000000..946aeea --- /dev/null +++ b/sys/netiso/iso_var.h @@ -0,0 +1,137 @@ +/*- + * Copyright (c) 1988, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)iso_var.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: iso_var.h,v 4.2 88/06/29 15:00:08 hagens Exp $ + * $Source: /usr/argo/sys/netiso/RCS/iso_var.h,v $ + */ + +/* + * Interface address, iso version. One of these structures is + * allocated for each interface with an osi address. The ifaddr + * structure conatins the protocol-independent part + * of the structure, and is assumed to be first. + */ +struct iso_ifaddr { + struct ifaddr ia_ifa; /* protocol-independent info */ +#define ia_ifp ia_ifa.ifa_ifp +#define ia_flags ia_ifa.ifa_flags + int ia_snpaoffset; + struct iso_ifaddr *ia_next; /* next in list of iso addresses */ + struct sockaddr_iso ia_addr; /* reserve space for interface name */ + struct sockaddr_iso ia_dstaddr; /* reserve space for broadcast addr */ +#define ia_broadaddr ia_dstaddr + struct sockaddr_iso ia_sockmask; /* reserve space for general netmask */ +}; + +struct iso_aliasreq { + char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_iso ifra_addr; + struct sockaddr_iso ifra_dstaddr; + struct sockaddr_iso ifra_mask; + int ifra_snpaoffset; +}; + +struct iso_ifreq { + char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + struct sockaddr_iso ifr_Addr; +}; + +/* + * Given a pointer to an iso_ifaddr (ifaddr), + * return a pointer to the addr as a sockaddr_iso + */ +/* +#define IA_SIS(ia) ((struct sockaddr_iso *)(ia.ia_ifa->ifa_addr)) + * works if sockaddr_iso becomes variable sized. + */ +#define IA_SIS(ia) (&(((struct iso_ifaddr *)ia)->ia_addr)) + +#define SIOCDIFADDR_ISO _IOW('i',25, struct iso_ifreq) /* delete IF addr */ +#define SIOCAIFADDR_ISO _IOW('i',26, struct iso_aliasreq)/* add/chg IFalias */ +#define SIOCGIFADDR_ISO _IOWR('i',33, struct iso_ifreq) /* get ifnet address */ +#define SIOCGIFDSTADDR_ISO _IOWR('i',34, struct iso_ifreq) /* get dst address */ +#define SIOCGIFNETMASK_ISO _IOWR('i',37, struct iso_ifreq) /* get dst address */ + +/* + * This stuff should go in if.h or if_llc.h or someplace else, + * but for now . . . + */ + +struct llc_etherhdr { + char dst[6]; + char src[6]; + char len[2]; + char llc_dsap; + char llc_ssap; + char llc_ui_byte; +}; + +struct snpa_hdr { + struct ifnet *snh_ifp; + char snh_dhost[6]; + char snh_shost[6]; + short snh_flags; +}; +#ifdef KERNEL +struct iso_ifaddr *iso_ifaddr; /* linked list of iso address ifaces */ +struct iso_ifaddr *iso_localifa(); /* linked list of iso address ifaces */ +struct ifqueue clnlintrq; /* clnl packet input queue */ +#endif /* KERNEL */ diff --git a/sys/netiso/tp.trans b/sys/netiso/tp.trans new file mode 100644 index 0000000..edefc76 --- /dev/null +++ b/sys/netiso/tp.trans @@ -0,0 +1,1342 @@ +/* NEW */ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp.trans 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* $Header: tp.trans,v 5.1 88/10/12 12:22:07 root Exp $ + * + * Transition file for TP. + * + * DO NOT: + * - change the order of any of the events or states. to do so will + * make tppt, netstat, etc. cease working. + * + * NOTE: + * some hooks exist for data on (dis)connect, but it's ***NOT***SUPPORTED*** + * (read: may not work!) + * + * I tried to put everything that causes a change of state in here, hence + * there are some seemingly trivial events like T_DETACH and T_LISTEN_req. + * + * Almost everything having to do w/ setting & cancelling timers is here + * but once it was debugged, I moved the setting of the + * keepalive (sendack) timer to tp_emit(), where an AK_TPDU is sent. + * This is so the code wouldn't be duplicated all over creation in here. + * + */ +*PROTOCOL tp + +*INCLUDE +{ +/* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/mbuf.h> +#include <sys/time.h> +#include <sys/errno.h> + +#include <netiso/tp_param.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> +#include <netiso/iso_errno.h> +#include <netiso/tp_seq.h> +#include <netiso/cons.h> + +#define DRIVERTRACE TPPTdriver +#define sbwakeup(sb) sowakeup(p->tp_sock, sb); +#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) + +static trick_hc = 1; + +int tp_emit(), + tp_goodack(), tp_goodXack(), + tp_stash() +; +void tp_indicate(), tp_getoptions(), + tp_soisdisconnecting(), tp_soisdisconnected(), + tp_recycle_tsuffix(), +#ifdef TP_DEBUG_TIMERS + tp_etimeout(), tp_euntimeout(), + tp_ctimeout(), tp_cuntimeout(), + tp_ctimeout_MIN(), +#endif + tp_freeref(), tp_detach(), + tp0_stash(), tp0_send(), + tp_netcmd(), tp_send() +; + +typedef struct tp_pcb tpcb_struct; + + +} + +*PCB tpcb_struct SYNONYM P + +*STATES + +TP_CLOSED +TP_CRSENT +TP_AKWAIT +TP_OPEN +TP_CLOSING +TP_REFWAIT +TP_LISTENING /* Local to this implementation */ +TP_CONFIRMING /* Local to this implementation */ + +*EVENTS { struct timeval e_time; } SYNONYM E + + /* + * C (typically cancelled) timers - + * + * let these be the first ones so for the sake of convenience + * their values are 0--> n-1 + * DO NOT CHANGE THE ORDER OF THESE TIMER EVENTS!! + */ + TM_inact + TM_retrans + /* TM_retrans is used for all + * simple retransmissions - CR,CC,XPD,DR + */ + + TM_sendack + /* TM_sendack does dual duty - keepalive AND closed-window + * Probes. + * It's set w/ keepalive-ticks every time an ack is sent. + * (this is done in (void) tp_emit() ). + * Whenever a DT arrives which doesn't require immediate acking, + * a separate fast-timeout flag is set ensuring 200ms response. + */ + TM_notused + + /* + * E (typically expired) timers - these may be in any order. + * These cause procedures to be executed directly; may not + * cause an 'event' as we know them here. + */ + TM_reference { SeqNum e_low; SeqNum e_high; int e_retrans; } + TM_data_retrans { SeqNum e_low; SeqNum e_high; int e_retrans; } + +/* NOTE: in tp_input is a minor optimization that assumes that + * for all tpdu types that can take e_data and e_datalen, these + * fields fall in the same place in the event structure, that is, + * e_data is the first field and e_datalen is the 2nd field. + */ + + ER_TPDU { + u_char e_reason; + } + CR_TPDU { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_int e_cdt; + } + DR_TPDU { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_short e_sref; + u_char e_reason; + } + DC_TPDU + CC_TPDU { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_short e_sref; + u_int e_cdt; + } + AK_TPDU { u_int e_cdt; + SeqNum e_seq; + SeqNum e_subseq; + u_char e_fcc_present; + } + DT_TPDU { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_int e_eot; + SeqNum e_seq; + } + XPD_TPDU { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + SeqNum e_seq; + } + XAK_TPDU { SeqNum e_seq; } + + T_CONN_req + T_DISC_req { u_char e_reason; } + T_LISTEN_req + T_DATA_req + T_XPD_req + T_USR_rcvd + T_USR_Xrcvd + T_DETACH + T_NETRESET + T_ACPT_req + + +*TRANSITIONS + + +/* TP_AKWAIT doesn't exist in TP 0 */ +SAME <== TP_AKWAIT [ CC_TPDU, DC_TPDU, XAK_TPDU ] + DEFAULT + NULLACTION +; + + +/* applicable in TP4, TP0 */ +SAME <== TP_REFWAIT DR_TPDU + ( $$.e_sref != 0 ) + { + (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); + } +; + +/* applicable in TP4, TP0 */ +SAME <== TP_REFWAIT [ CR_TPDU, CC_TPDU, DT_TPDU, + DR_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU, DC_TPDU, ER_TPDU ] + DEFAULT + { +# ifdef TP_DEBUG + if( $E.ev_number != AK_TPDU ) + printf("TPDU 0x%x in REFWAIT!!!!\n", $E.ev_number); +# endif TP_DEBUG + } +; + +/* applicable in TP4, TP0 */ +SAME <== TP_REFWAIT [ T_DETACH, T_DISC_req ] + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +SAME <== TP_CRSENT AK_TPDU + ($P.tp_class == TP_CLASS_0) + { + /* oh, man is this grotesque or what? */ + (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); + /* but it's necessary because this pseudo-ack may happen + * before the CC arrives, but we HAVE to adjust the + * snduna as a result of the ack, WHENEVER it arrives + */ + } +; + +/* applicable in TP4, TP0 */ +SAME <== TP_CRSENT + [ CR_TPDU, DC_TPDU, DT_TPDU, XPD_TPDU, XAK_TPDU ] + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +SAME <== TP_CLOSED [ DT_TPDU, XPD_TPDU, + ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] + DEFAULT + NULLACTION +; + +/* TP_CLOSING doesn't exist in TP 0 */ +SAME <== TP_CLOSING + [ CC_TPDU, CR_TPDU, DT_TPDU, XPD_TPDU, AK_TPDU, XAK_TPDU ] + DEFAULT + NULLACTION +; + + +/* DC_TPDU doesn't exist in TP 0 */ +SAME <== TP_OPEN DC_TPDU + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +SAME <== TP_LISTENING [DR_TPDU, CC_TPDU, DT_TPDU, XPD_TPDU, + ER_TPDU, DC_TPDU, AK_TPDU, XAK_TPDU ] + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +TP_LISTENING <== TP_CLOSED T_LISTEN_req + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +TP_CLOSED <== [ TP_LISTENING, TP_CLOSED ] T_DETACH + DEFAULT + { + tp_detach($P); + } +; + +TP_CONFIRMING <== TP_LISTENING CR_TPDU + ( $P.tp_class == TP_CLASS_0) + { + $P.tp_refstate = REF_OPEN; /* has timers ??? */ + } +; + +TP_CONFIRMING <== TP_LISTENING CR_TPDU + DEFAULT + { + IFTRACE(D_CONN) + tptrace(TPPTmisc, "CR datalen data", $$.e_datalen, $$.e_data,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("CR datalen 0x%x data 0x%x", $$.e_datalen, $$.e_data); + ENDDEBUG + $P.tp_refstate = REF_OPEN; /* has timers */ + $P.tp_fcredit = $$.e_cdt; + + if ($$.e_datalen > 0) { + /* n/a for class 0 */ + ASSERT($P.tp_Xrcv.sb_cc == 0); + sbappendrecord(&$P.tp_Xrcv, $$.e_data); + $$.e_data = MNULL; + } + } +; + +TP_OPEN <== TP_CONFIRMING T_ACPT_req + ( $P.tp_class == TP_CLASS_0 ) + { + IncStat(ts_tp0_conn); + IFTRACE(D_CONN) + tptrace(TPPTmisc, "Confiming", $P, 0,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("Confirming connection: $P" ); + ENDDEBUG + soisconnected($P.tp_sock); + (void) tp_emit(CC_TPDU_type, $P, 0,0, MNULL) ; + $P.tp_fcredit = 1; + } +; + +TP_AKWAIT <== TP_CONFIRMING T_ACPT_req + (tp_emit(CC_TPDU_type, $P, 0,0, MCPY($P.tp_ucddata, M_NOWAIT)) == 0) + { + IncStat(ts_tp4_conn); /* even though not quite open */ + IFTRACE(D_CONN) + tptrace(TPPTmisc, "Confiming", $P, 0,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("Confirming connection: $P" ); + ENDDEBUG + tp_getoptions($P); + soisconnecting($P.tp_sock); + if (($P.tp_rx_strat & TPRX_FASTSTART) && ($P.tp_fcredit > 0)) + $P.tp_cong_win = $P.tp_fcredit * $P.tp_l_tpdusize; + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); + } +; + +/* TP4 only */ +TP_CLOSED <== TP_CONFIRMING T_ACPT_req + DEFAULT /* emit failed */ + { + IFDEBUG(D_CONN) + printf("event: CR_TPDU emit CC failed done " ); + ENDDEBUG + soisdisconnected($P.tp_sock); + tp_recycle_tsuffix($P); + tp_freeref($P.tp_lref); + tp_detach($P); + } +; + +/* applicable in TP4, TP0 */ +TP_CRSENT <== TP_CLOSED T_CONN_req + DEFAULT + { + int error; + struct mbuf *data = MNULL; + + IFTRACE(D_CONN) + tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)$P.tp_flags, + $P.tp_ucddata, 0, 0); + ENDTRACE + data = MCPY($P.tp_ucddata, M_WAIT); + if (data) { + IFDEBUG(D_CONN) + printf("T_CONN_req.trans m_copy cc 0x%x\n", + $P.tp_ucddata); + dump_mbuf(data, "sosnd @ T_CONN_req"); + ENDDEBUG + } + + if (error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) + return error; /* driver WON'T change state; will return error */ + + $P.tp_refstate = REF_OPEN; /* has timers */ + if($P.tp_class != TP_CLASS_0) { + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); + } + } +; + +/* applicable in TP4, TP0, but state TP_AKWAIT doesn't apply to TP0 */ +TP_REFWAIT <== [ TP_CRSENT, TP_AKWAIT, TP_OPEN ] DR_TPDU + DEFAULT + { + sbflush(&$P.tp_Xrcv); /* purge non-delivered data data */ + if ($$.e_datalen > 0) { + sbappendrecord(&$P.tp_Xrcv, $$.e_data); + $$.e_data = MNULL; + } + if ($P.tp_state == TP_OPEN) + tp_indicate(T_DISCONNECT, $P, 0); + else { + int so_error = ECONNREFUSED; + if ($$.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && + $$.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && + $$.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) + so_error = ECONNABORTED; + tp_indicate(T_DISCONNECT, $P, so_error); + } + tp_soisdisconnected($P); + if ($P.tp_class != TP_CLASS_0) { + if ($P.tp_state == TP_OPEN ) { + tp_euntimeout($P, TM_data_retrans); /* all */ + tp_cuntimeout($P, TM_retrans); + tp_cuntimeout($P, TM_inact); + tp_cuntimeout($P, TM_sendack); + $P.tp_flags &= ~TPF_DELACK; + } + tp_cuntimeout($P, TM_retrans); + if( $$.e_sref != 0 ) + (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); + } + } +; + +SAME <== TP_CLOSED DR_TPDU + DEFAULT + { + if( $$.e_sref != 0 ) + (void) tp_emit(DC_TPDU_type, $P, 0, 0, MNULL); + /* reference timer already set - reset it to be safe (???) */ + tp_euntimeout($P, TM_reference); /* all */ + tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); + } +; + +/* NBS(34) */ +TP_REFWAIT <== TP_CRSENT ER_TPDU + DEFAULT + { + tp_cuntimeout($P, TM_retrans); + tp_indicate(ER_TPDU, $P, $$.e_reason); + tp_soisdisconnected($P); + } +; + +/* NBS(27) */ +TP_REFWAIT <== TP_CLOSING DR_TPDU + DEFAULT + { + tp_cuntimeout($P, TM_retrans); + tp_soisdisconnected($P); + } +; +/* these two transitions are the same but can't be combined because xebec + * can't handle the use of $$.e_reason if they're combined + */ +/* NBS(27) */ +TP_REFWAIT <== TP_CLOSING ER_TPDU + DEFAULT + { + tp_indicate(ER_TPDU, $P, $$.e_reason); + tp_cuntimeout($P, TM_retrans); + tp_soisdisconnected($P); + } +; +/* NBS(27) */ +TP_REFWAIT <== TP_CLOSING DC_TPDU + DEFAULT + { + tp_cuntimeout($P, TM_retrans); + tp_soisdisconnected($P); + } +; + +/* NBS(21) */ +SAME <== TP_CLOSED [ CC_TPDU, CR_TPDU ] + DEFAULT + { /* don't ask me why we have to do this - spec says so */ + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NO_SESSION, MNULL); + /* don't bother with retransmissions of the DR */ + } +; + +/* NBS(34) */ +TP_REFWAIT <== TP_OPEN ER_TPDU + ($P.tp_class == TP_CLASS_0) + { + tp_soisdisconnecting($P.tp_sock); + tp_indicate(ER_TPDU, $P, $$.e_reason); + tp_soisdisconnected($P); + tp_netcmd( $P, CONN_CLOSE ); + } +; + +TP_CLOSING <== [ TP_AKWAIT, TP_OPEN ] ER_TPDU + DEFAULT + { + if ($P.tp_state == TP_OPEN) { + tp_euntimeout($P, TM_data_retrans); /* all */ + tp_cuntimeout($P, TM_inact); + tp_cuntimeout($P, TM_sendack); + } + tp_soisdisconnecting($P.tp_sock); + tp_indicate(ER_TPDU, $P, $$.e_reason); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_PROTO_ERR, MNULL); + } +; +/* NBS(6) */ +TP_OPEN <== TP_CRSENT CC_TPDU + ($P.tp_class == TP_CLASS_0) + { + tp_cuntimeout($P, TM_retrans); + IncStat(ts_tp0_conn); + $P.tp_fcredit = 1; + soisconnected($P.tp_sock); + } +; + +TP_OPEN <== TP_CRSENT CC_TPDU + DEFAULT + { + IFDEBUG(D_CONN) + printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", + (int)$P.tp_flags); + ENDDEBUG + IncStat(ts_tp4_conn); + $P.tp_fref = $$.e_sref; + $P.tp_fcredit = $$.e_cdt; + if (($P.tp_rx_strat & TPRX_FASTSTART) && ($$.e_cdt > 0)) + $P.tp_cong_win = $$.e_cdt * $P.tp_l_tpdusize; + tp_getoptions($P); + tp_cuntimeout($P, TM_retrans); + if ($P.tp_ucddata) { + IFDEBUG(D_CONN) + printf("dropping user connect data cc 0x%x\n", + $P.tp_ucddata->m_len); + ENDDEBUG + m_freem($P.tp_ucddata); + $P.tp_ucddata = 0; + } + soisconnected($P.tp_sock); + if ($$.e_datalen > 0) { + ASSERT($P.tp_Xrcv.sb_cc == 0); /* should be empty */ + sbappendrecord(&$P.tp_Xrcv, $$.e_data); + $$.e_data = MNULL; + } + + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } +; + +/* TP4 only */ +SAME <== TP_CRSENT TM_retrans + ( $P.tp_retrans > 0 ) + { + struct mbuf *data = MNULL; + int error; + + IncStat(ts_retrans_cr); + $P.tp_cong_win = 1 * $P.tp_l_tpdusize; + data = MCPY($P.tp_ucddata, M_NOWAIT); + if($P.tp_ucddata) { + IFDEBUG(D_CONN) + printf("TM_retrans.trans m_copy cc 0x%x\n", data); + dump_mbuf($P.tp_ucddata, "sosnd @ TM_retrans"); + ENDDEBUG + if( data == MNULL ) + return ENOBUFS; + } + + $P.tp_retrans --; + if( error = tp_emit(CR_TPDU_type, $P, 0, 0, data) ) { + $P.tp_sock->so_error = error; + } + tp_ctimeout($P, TM_retrans, (int)$P.tp_cr_ticks); + } +; + +/* TP4 only */ +TP_REFWAIT <== TP_CRSENT TM_retrans + DEFAULT /* no more CR retransmissions */ + { + IncStat(ts_conn_gaveup); + $P.tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); + tp_soisdisconnected($P); + } +; + +/* TP4 only */ +SAME <== TP_AKWAIT CR_TPDU + DEFAULT + /* duplicate CR (which doesn't really exist in the context of + * a connectionless network layer) + * Doesn't occur in class 0. + */ + { + int error; + struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); + + if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) { + $P.tp_sock->so_error = error; + } + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); + } +; + +/* TP4 only */ +TP_OPEN <== TP_AKWAIT DT_TPDU + ( IN_RWINDOW( $P, $$.e_seq, + $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) + { + int doack; + + /* + * Get rid of any confirm or connect data, so that if we + * crash or close, it isn't thought of as disconnect data. + */ + if ($P.tp_ucddata) { + m_freem($P.tp_ucddata); + $P.tp_ucddata = 0; + } + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + tp_cuntimeout($P, TM_retrans); + soisconnected($P.tp_sock); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + + /* see also next 2 transitions, if you make any changes */ + + doack = tp_stash($P, $E); + IFDEBUG(D_DATA) + printf("tp_stash returns %d\n",doack); + ENDDEBUG + + if (doack) { + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); + tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); + } else + tp_ctimeout( $P, TM_sendack, (int)$P.tp_sendack_ticks); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } +; + +SAME <== TP_OPEN DT_TPDU + ( $P.tp_class == TP_CLASS_0 ) + { + tp0_stash($P, $E); + sbwakeup( &$P.tp_sock->so_rcv ); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } +; + +/* TP4 only */ +SAME <== TP_OPEN DT_TPDU + ( IN_RWINDOW( $P, $$.e_seq, + $P.tp_rcvnxt, SEQ($P, $P.tp_rcvnxt + $P.tp_lcredit)) ) + { + int doack; /* tells if we must ack immediately */ + + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + sbwakeup( &$P.tp_sock->so_rcv ); + + doack = tp_stash($P, $E); + IFDEBUG(D_DATA) + printf("tp_stash returns %d\n",doack); + ENDDEBUG + + if(doack) + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); + else + tp_ctimeout_MIN( $P, TM_sendack, (int)$P.tp_sendack_ticks); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } +; + +/* Not in window - we must ack under certain circumstances, namely + * a) if the seq number is below lwe but > lwe - (max credit ever given) + * (to handle lost acks) Can use max-possible-credit for this ^^^. + * and + * b) seq number is > uwe but < uwe + previously sent & withdrawn credit + * + * (see 12.2.3.8.1 of ISO spec, p. 73) + * We just always ack. + */ +/* TP4 only */ +SAME <== [ TP_OPEN, TP_AKWAIT ] DT_TPDU + DEFAULT /* Not in window */ + { + IFTRACE(D_DATA) + tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", + $$.e_seq, $P.tp_rcvnxt, $P.tp_lcredit, 0); + ENDTRACE + IncStat(ts_dt_niw); + m_freem($$.e_data); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL ); + } +; + +/* TP4 only */ +TP_OPEN <== TP_AKWAIT AK_TPDU + DEFAULT + { + if ($P.tp_ucddata) { + m_freem($P.tp_ucddata); + $P.tp_ucddata = 0; + } + (void) tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq); + tp_cuntimeout($P, TM_retrans); + + soisconnected($P.tp_sock); + IFTRACE(D_CONN) + struct socket *so = $P.tp_sock; + tptrace(TPPTmisc, + "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", + so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); + tptrace(TPPTmisc, + "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", + so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); + ENDTRACE + + tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } +; + +/* TP4 only */ +TP_OPEN <== [ TP_OPEN, TP_AKWAIT ] XPD_TPDU + ($P.tp_Xrcvnxt == $$.e_seq) + { + if( $P.tp_state == TP_AKWAIT ) { + if ($P.tp_ucddata) { + m_freem($P.tp_ucddata); + $P.tp_ucddata = 0; + } + tp_cuntimeout($P, TM_retrans); + soisconnected($P.tp_sock); + tp_ctimeout($P, TM_sendack, (int)$P.tp_keepalive_ticks); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", + $P.tp_Xrcvnxt,$$.e_seq, $$.e_datalen, $$.e_data->m_len); + ENDTRACE + + $P.tp_sock->so_state |= SS_RCVATMARK; + $$.e_data->m_flags |= M_EOR; + sbinsertoob(&$P.tp_Xrcv, $$.e_data); + IFDEBUG(D_XPD) + dump_mbuf($$.e_data, "XPD TPDU: tp_Xrcv"); + ENDDEBUG + tp_indicate(T_XDATA, $P, 0); + sbwakeup( &$P.tp_Xrcv ); + + (void) tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); + SEQ_INC($P, $P.tp_Xrcvnxt); + } +; + +/* TP4 only */ +SAME <== TP_OPEN T_USR_Xrcvd + DEFAULT + { + if( $P.tp_Xrcv.sb_cc == 0 ) { + /* kludge for select(): */ + /* $P.tp_sock->so_state &= ~SS_OOBAVAIL; */ + } + } + /* OLD WAY: + * Ack only after the user receives the XPD. This is better for + * users that use one XPD right after another. + * Acking right away (the NEW WAY, see the prev. transition) is + * better for occasional * XPD, when the receiving user doesn't + * want to read the XPD immediately (which is session's behavior). + * + int error = tp_emit(XAK_TPDU_type, $P, $P.tp_Xrcvnxt, 0, MNULL); + SEQ_INC($P, $P.tp_Xrcvnxt); + return error; + */ +; + +/* NOTE: presently if the user doesn't read the connection data + * before and expedited data PDU comes in, the connection data will + * be dropped. This is a bug. To avoid it, we need somewhere else + * to put the connection data. + * On the other hand, we need not to have it sitting around forever. + * This is a problem with the idea of trying to accommodate + * data on connect w/ a passive-open user interface. + */ +/* TP4 only */ + +SAME <== [ TP_AKWAIT, TP_OPEN ] XPD_TPDU + DEFAULT /* not in window or cdt==0 */ + { + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", + $P.tp_Xrcvnxt, $$.e_seq, $P.tp_Xrcv.sb_cc , 0); + ENDTRACE + if( $P.tp_Xrcvnxt != $$.e_seq ) + IncStat(ts_xpd_niw); + if( $P.tp_Xrcv.sb_cc ) { + /* might as well kick 'em again */ + tp_indicate(T_XDATA, $P, 0); + IncStat(ts_xpd_dup); + } + m_freem($$.e_data); + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + /* don't send an xack because the xak gives "last one received", not + * "next one i expect" (dumb) + */ + } +; + +/* Occurs (AKWAIT, OPEN) when parent (listening) socket gets aborted, and tries + * to detach all its "children" + * Also (CRSENT) when user kills a job that's doing a connect() + */ +TP_REFWAIT <== TP_CRSENT T_DETACH + ($P.tp_class == TP_CLASS_0) + { + struct socket *so = $P.tp_sock; + + /* detach from parent socket so it can finish closing */ + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp: T_DETACH"); + so->so_head = 0; + } + tp_soisdisconnecting($P.tp_sock); + tp_netcmd( $P, CONN_CLOSE); + tp_soisdisconnected($P); + } +; + +/* TP4 only */ +TP_CLOSING <== [ TP_CLOSING, TP_AKWAIT, TP_CRSENT, TP_CONFIRMING ] T_DETACH + DEFAULT + { + struct socket *so = $P.tp_sock; + struct mbuf *data = MNULL; + + /* detach from parent socket so it can finish closing */ + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp: T_DETACH"); + so->so_head = 0; + } + if ($P.tp_state != TP_CLOSING) { + tp_soisdisconnecting($P.tp_sock); + data = MCPY($P.tp_ucddata, M_NOWAIT); + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_NORMAL_DISC, data); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + } + } +; + +TP_REFWAIT <== [ TP_OPEN, TP_CRSENT ] T_DISC_req + ( $P.tp_class == TP_CLASS_0 ) + { + tp_soisdisconnecting($P.tp_sock); + tp_netcmd( $P, CONN_CLOSE); + tp_soisdisconnected($P); + } +; + +/* TP4 only */ +TP_CLOSING <== [ TP_AKWAIT, TP_OPEN, TP_CRSENT, TP_CONFIRMING ] T_DISC_req + DEFAULT + { + struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); + + if($P.tp_state == TP_OPEN) { + tp_euntimeout($P, TM_data_retrans); /* all */ + tp_cuntimeout($P, TM_inact); + tp_cuntimeout($P, TM_sendack); + $P.tp_flags &= ~TPF_DELACK; + } + if (data) { + IFDEBUG(D_CONN) + printf("T_DISC_req.trans tp_ucddata 0x%x\n", + $P.tp_ucddata); + dump_mbuf(data, "ucddata @ T_DISC_req"); + ENDDEBUG + } + tp_soisdisconnecting($P.tp_sock); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + + if( trick_hc ) + return tp_emit(DR_TPDU_type, $P, 0, $$.e_reason, data); + } +; + +/* TP4 only */ +SAME <== TP_AKWAIT TM_retrans + ( $P.tp_retrans > 0 ) + { + int error; + struct mbuf *data = MCPY($P.tp_ucddata, M_WAIT); + + IncStat(ts_retrans_cc); + $P.tp_retrans --; + $P.tp_cong_win = 1 * $P.tp_l_tpdusize; + + if( error = tp_emit(CC_TPDU_type, $P, 0, 0, data) ) + $P.tp_sock->so_error = error; + tp_ctimeout($P, TM_retrans, (int)$P.tp_cc_ticks); + } +; + +/* TP4 only */ +TP_CLOSING <== TP_AKWAIT TM_retrans + DEFAULT /* out of time */ + { + IncStat(ts_conn_gaveup); + tp_soisdisconnecting($P.tp_sock); + $P.tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST, MNULL); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + } +; + +/* the retrans timers had better go off BEFORE the inactivity timer does, + * if transmissions are going on. + * (i.e., TM_inact should be greater than timer for all retrans plus ack + * turnaround) + */ +/* TP4 only */ +TP_CLOSING <== TP_OPEN [ TM_inact, TM_retrans, TM_data_retrans ] + DEFAULT + { + tp_euntimeout($P, TM_data_retrans); /* all */ + tp_cuntimeout($P, TM_inact); + tp_cuntimeout($P, TM_sendack); + + IncStat(ts_conn_gaveup); + tp_soisdisconnecting($P.tp_sock); + $P.tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, $P, ETIMEDOUT); + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_CONGEST_2, MNULL); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + } +; + +/* TP4 only */ +SAME <== TP_OPEN TM_retrans + ( $P.tp_retrans > 0 ) + { + $P.tp_cong_win = 1 * $P.tp_l_tpdusize; + /* resume XPD */ + if ( $P.tp_Xsnd.sb_mb ) { + struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); + int shift; + + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", + $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, + $P.tp_snduna); + ENDTRACE + IFDEBUG(D_XPD) + dump_mbuf(m, "XPD retrans emitting M"); + ENDDEBUG + IncStat(ts_retrans_xpd); + $P.tp_retrans --; + shift = max($P.tp_Nretrans - $P.tp_retrans, 6); + (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); + tp_ctimeout($P, TM_retrans, ((int)$P.tp_dt_ticks) << shift); + } + } +; + +/* TP4 only */ +SAME <== TP_OPEN TM_data_retrans + ($P.tp_rxtshift < TP_NRETRANS) + { + $P.tp_rxtshift++; + (void) tp_data_retrans($P); + } +; + +/* TP4 only */ +SAME <== TP_CLOSING TM_retrans + ( $P.tp_retrans > 0 ) + { + $P.tp_retrans --; + (void) tp_emit(DR_TPDU_type, $P, 0, E_TP_DR_NO_REAS, MNULL); + IncStat(ts_retrans_dr); + tp_ctimeout($P, TM_retrans, (int)$P.tp_dr_ticks); + } +; + +/* TP4 only */ +TP_REFWAIT <== TP_CLOSING TM_retrans + DEFAULT /* no more retrans - gave up */ + { + $P.tp_sock->so_error = ETIMEDOUT; + $P.tp_refstate = REF_FROZEN; + tp_recycle_tsuffix( $P ); + tp_etimeout($P, TM_reference, (int)$P.tp_refer_ticks); + } +; + +/* + * The resources are kept around until the ref timer goes off. + * The suffices are wiped out sooner so they can be reused right away. + */ +/* applicable in TP4, TP0 */ +TP_CLOSED <== TP_REFWAIT TM_reference + DEFAULT + { + tp_freeref($P.tp_lref); + tp_detach($P); + } +; + +/* applicable in TP4, TP0 */ +/* A duplicate CR from connectionless network layer can't happen */ +SAME <== TP_OPEN [ CR_TPDU, CC_TPDU ] + DEFAULT + { + if( $P.tp_class != TP_CLASS_0) { + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + if ( $E.ev_number == CC_TPDU ) + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); + } + /* ignore it if class 0 - state tables are blank for this */ + } +; + +/* applicable in TP4, TP0 */ +SAME <== TP_OPEN T_DATA_req + DEFAULT + { + IFTRACE(D_DATA) + tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", + $P.tp_sndnxt, $P.tp_snduna, $P.tp_fcredit, $P); + ENDTRACE + + tp_send($P); + } +; + +/* TP4 only */ +SAME <== TP_OPEN T_XPD_req + DEFAULT + /* T_XPD_req was issued by sosend iff xpd socket buf was empty + * at time of sosend(), + * AND (which means) there were no unacknowledged XPD tpdus outstanding! + */ + { + int error = 0; + + /* resume XPD */ + if ( $P.tp_Xsnd.sb_mb ) { + struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, (int)$P.tp_Xsnd.sb_cc); + /* m_copy doesn't preserve the m_xlink field, but at this pt. + * that doesn't matter + */ + + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", + $P.tp_Xuna, $P.tp_Xsndnxt, $P.tp_sndnxt, + $P.tp_snduna); + ENDTRACE + IFDEBUG(D_XPD) + printf("T_XPD_req: sb_cc 0x%x\n", $P.tp_Xsnd.sb_cc); + dump_mbuf(m, "XPD req emitting M"); + ENDDEBUG + error = + tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); + $P.tp_retrans = $P.tp_Nretrans; + + tp_ctimeout($P, TM_retrans, (int)$P.tp_rxtcur); + SEQ_INC($P, $P.tp_Xsndnxt); + } + if(trick_hc) + return error; + } +; + +/* TP4, faked ack in TP0 when cons send completes */ +SAME <== TP_OPEN AK_TPDU + ( tp_goodack($P, $$.e_cdt, $$.e_seq, $$.e_subseq) ) + + /* tp_goodack == true means + * EITHER it actually acked something heretofore unacknowledged + * OR no news but the credit should be processed. + */ + { + struct sockbuf *sb = &$P.tp_sock->so_snd; + + IFDEBUG(D_ACKRECV) + printf("GOOD ACK seq 0x%x cdt 0x%x\n", $$.e_seq, $$.e_cdt); + ENDDEBUG + if( $P.tp_class != TP_CLASS_0) { + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } + sbwakeup(sb); + IFDEBUG(D_ACKRECV) + printf("GOOD ACK new sndnxt 0x%x\n", $P.tp_sndnxt); + ENDDEBUG + } +; + +/* TP4, and TP0 after sending a CC or possibly a CR */ +SAME <== TP_OPEN AK_TPDU + DEFAULT + { + IFTRACE(D_ACKRECV) + tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", + $$.e_fcc_present, $P.tp_r_subseq, $$.e_subseq, 0); + ENDTRACE + if( $P.tp_class != TP_CLASS_0 ) { + + if ( !$$.e_fcc_present ) { + /* send ACK with FCC */ + IncStat( ts_ackreason[_ACK_FCC_] ); + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 1, MNULL); + } + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } + } +; + +/* NBS(47) */ + /* goes in at *** */ + /* just so happens that this is never true now, because we allow + * only 1 packet in the queue at once (this could be changed) + if ( $P.tp_Xsnd.sb_mb ) { + struct mbuf *m = m_copy($P.tp_Xsnd.sb_mb, 0, ??); + + (void) tp_emit(XPD_TPDU_type, $P, $P.tp_Xuna, 1, m); + $P.tp_retrans = $P.tp_Nretrans; + tp_ctimeout($P, TM_retrans, (int)$P.tp_xpd_ticks); + SEQ_INC($P, $P.tp_Xsndnxt); + } + */ + /* end of the above hack */ + +/* TP4 only */ +SAME <== TP_OPEN XAK_TPDU + ( tp_goodXack($P, $$.e_seq) ) + /* tp_goodXack checks for good ack, removes the correct + * tpdu from the queue and returns 1 if ack was legit, 0 if not. + * also updates tp_Xuna + */ + { + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + tp_cuntimeout($P, TM_retrans); + + sbwakeup( &$P.tp_sock->so_snd ); + + /* resume normal data */ + tp_send($P); + } +; + +/* TP4, and TP0 after sending a CC or possibly a CR */ +SAME <== TP_OPEN XAK_TPDU + DEFAULT + { + IFTRACE(D_ACKRECV) + tptrace(TPPTmisc, "BOGUS XACK eventtype ", $E.ev_number, 0, 0,0); + ENDTRACE + if( $P.tp_class != TP_CLASS_0 ) { + tp_ctimeout($P, TM_inact, (int)$P.tp_inact_ticks); + } + } +; + +/* TP4 only */ +SAME <== TP_OPEN TM_sendack + DEFAULT + { + int timo; + IFTRACE(D_TIMER) + tptrace(TPPTsendack, -1, $P.tp_lcredit, $P.tp_sent_uwe, + $P.tp_sent_lcdt, 0); + ENDTRACE + IncPStat($P, tps_n_TMsendack); + (void) tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); + if ($P.tp_fcredit == 0) { + if ($P.tp_rxtshift < TP_MAXRXTSHIFT) + $P.tp_rxtshift++; + timo = ($P.tp_dt_ticks) << $P.tp_rxtshift; + } else + timo = $P.tp_sendack_ticks; + tp_ctimeout($P, TM_sendack, timo); + } +; + +/* TP0 only */ +SAME <== TP_OPEN T_USR_rcvd + ($P.tp_class == TP_CLASS_0) + { + if (sbspace(&$P.tp_sock->so_rcv) > 0) + tp0_openflow($P); + } +; + +/* TP4 only */ + /* If old credit was zero, + * we'd better inform other side that we now have space + * But this is not enough. Sender might not yet have + * seen an ack with cdt 0 but it might still think the + * window is closed, so it's going to wait. + * Best to send an ack each time. + * Strictly speaking, this ought to be a function of the + * general ack strategy. + */ +SAME <== TP_OPEN T_USR_rcvd + DEFAULT + { + if( trick_hc ) { + SeqNum ack_thresh; + /* + * If the upper window edge has advanced a reasonable + * amount beyond what was known, send an ACK. + * A reasonable amount is 2 packets, unless the max window + * is only 1 or 2 packets, in which case we + * should send an ack for any advance in the upper window edge. + */ + LOCAL_CREDIT($P); + ack_thresh = SEQ_SUB($P, $P.tp_lcredit + $P.tp_rcvnxt, + ($P.tp_maxlcredit > 2 ? 2 : 1)); + if (SEQ_GT($P, ack_thresh, $P.tp_sent_uwe)) { + IncStat(ts_ackreason[_ACK_USRRCV_]); + $P.tp_flags &= ~TPF_DELACK; + return tp_emit(AK_TPDU_type, $P, $P.tp_rcvnxt, 0, MNULL); + } + } + } +; + +/* applicable in TP4, TP0 */ +SAME <== TP_REFWAIT [ T_USR_rcvd, T_USR_Xrcvd ] + DEFAULT + /* This happens if other end sent a DR when the user was waiting + * on a receive. + * Processing the DR includes putting us in REFWAIT state. + */ + { + if(trick_hc) + return ECONNABORTED; + } +; + +/* TP0 only */ +TP_REFWAIT <== [ TP_OPEN, TP_CRSENT, TP_LISTENING ] T_NETRESET + ( $P.tp_class != TP_CLASS_4 ) + /* 0 or (4 and 0) */ + /* in OPEN class will be 0 or 4 but not both */ + /* in CRSENT or LISTENING it could be in negotiation, hence both */ + /* Actually, this shouldn't ever happen in LISTENING */ + { + ASSERT( $P.tp_state != TP_LISTENING ); + tp_indicate(T_DISCONNECT, $P, ECONNRESET); + tp_soisdisconnected($P); + } +; + +/* TP4: ignore resets */ +SAME <== [ TP_OPEN, TP_CRSENT, TP_AKWAIT, + TP_CLOSING, TP_LISTENING ] T_NETRESET + DEFAULT + NULLACTION +; + +/* applicable in TP4, TP0 */ +SAME <== [ TP_CLOSED, TP_REFWAIT ] T_NETRESET + DEFAULT + NULLACTION +; + +/* C'EST TOUT */ diff --git a/sys/netiso/tp_astring.c b/sys/netiso/tp_astring.c new file mode 100644 index 0000000..af08ceb --- /dev/null +++ b/sys/netiso/tp_astring.c @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_astring.c 8.1 (Berkeley) 6/10/93 + */ + +char *tp_sstring[] = { +"ST_ERROR(0x0)", +"TP_CLOSED(0x1)", +"TP_CRSENT(0x2)", +"TP_AKWAIT(0x3)", +"TP_OPEN(0x4)", +"TP_CLOSING(0x5)", +"TP_REFWAIT(0x6)", +"TP_LISTENING(0x7)", +"TP_CONFIRMING(0x8)", +}; + +char *tp_estring[] = { +"TM_inact(0x0)", +"TM_retrans(0x1)", +"TM_sendack(0x2)", +"TM_notused(0x3)", +"TM_reference(0x4)", +"TM_data_retrans(0x5)", +"ER_TPDU(0x6)", +"CR_TPDU(0x7)", +"DR_TPDU(0x8)", +"DC_TPDU(0x9)", +"CC_TPDU(0xa)", +"AK_TPDU(0xb)", +"DT_TPDU(0xc)", +"XPD_TPDU(0xd)", +"XAK_TPDU(0xe)", +"T_CONN_req(0xf)", +"T_DISC_req(0x10)", +"T_LISTEN_req(0x11)", +"T_DATA_req(0x12)", +"T_XPD_req(0x13)", +"T_USR_rcvd(0x14)", +"T_USR_Xrcvd(0x15)", +"T_DETACH(0x16)", +"T_NETRESET(0x17)", +"T_ACPT_req(0x18)", +}; diff --git a/sys/netiso/tp_clnp.h b/sys/netiso/tp_clnp.h new file mode 100644 index 0000000..81a7cff --- /dev/null +++ b/sys/netiso/tp_clnp.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_clnp.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_clnp.h,v 5.1 88/10/12 12:16:36 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_clnp.h,v $ + * + * AF_ISO net-dependent structures and include files + * + */ + + +#ifndef __TP_CLNP__ +#define __TP_CLNP__ + +#ifndef SOCK_STREAM +#include <sys/socket.h> +#endif /* SOCK_STREAM */ + +#ifndef RTFREE +#include <net/route.h> +#endif +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/iso_pcb.h> +#ifndef IF_DEQUEUE +#include <net/if.h> +#endif +#include <netiso/iso_var.h> + +struct isopcb tp_isopcb; + /* queue of active inpcbs for tp ; for tp with dod ip */ + +#endif /* __TP_CLNP__ */ diff --git a/sys/netiso/tp_cons.c b/sys/netiso/tp_cons.c new file mode 100644 index 0000000..797ee9e --- /dev/null +++ b/sys/netiso/tp_cons.c @@ -0,0 +1,308 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_cons.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * $Header: tp_cons.c,v 5.6 88/11/18 17:27:13 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_cons.c,v $ + * + * Here is where you find the iso- and cons-dependent code. We've tried + * keep all net-level and (primarily) address-family-dependent stuff + * out of the tp source, and everthing here is reached indirectly + * through a switch table (struct nl_protosw *) tpcb->tp_nlproto + * (see tp_pcb.c). + * The routines here are: + * tpcons_input: pullup and call tp_input w/ correct arguments + * tpcons_output: package a pkt for cons given an isopcb & some data + * cons_chan_to_tpcb: find a tpcb based on the channel # + */ + +#ifdef ISO +#ifdef TPCONS + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/domain.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/tp_param.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_tpdu.h> +#include <netiso/iso.h> +#include <netiso/iso_errno.h> +#include <netiso/iso_pcb.h> +#include <netiso/cons.h> +#include <netiso/tp_seq.h> + +#undef FALSE +#undef TRUE +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> + +#include <netiso/if_cons.c> +int tpcons_output(); + +/* + * CALLED FROM: + * tp_route_to() for PRU_CONNECT + * FUNCTION, ARGUMENTS, SIDE EFFECTS and RETURN VALUE: + * version of the previous procedure for X.25 + */ + +tpcons_pcbconnect(isop, nam) +struct isopcb *isop; +register struct mbuf *nam; +{ + int error; + if (error = iso_pcbconnect(isop, nam)) + return error; + if ((isop->isop_chan = (caddr_t) pk_attach((struct socket *)0)) == 0) { + IFDEBUG(D_CCONS) + printf("tpcons_pcbconnect: no pklcd; returns 0x%x\n", error); + ENDDEBUG + return ENOBUFS; + } + if (error = cons_connect(isop)) { /* if it doesn't work */ + /* oh, dear, throw packet away */ + pk_disconnect((struct pklcd *)isop->isop_chan); + isop->isop_chan = 0; + } else + isop->isop_refcnt = 1; + return error; +} + + +/* + * CALLED FROM: + * cons + * FUNCTION and ARGUMENTS: + * THIS MAYBE BELONGS IN SOME OTHER PLACE??? but i think not - + */ +ProtoHook +tpcons_ctlinput(cmd, siso, isop) + int cmd; + struct sockaddr_iso *siso; + struct isopcb *isop; +{ + register struct tp_pcb *tpcb = 0; + + if (isop->isop_socket) + tpcb = (struct tp_pcb *)isop->isop_socket->so_pcb; + switch (cmd) { + + case PRC_CONS_SEND_DONE: + if (tpcb) { + struct tp_event E; + int error = 0; + + if (tpcb->tp_class == TP_CLASS_0) { + /* only if class is exactly class zero, not + * still in class negotiation + */ + /* fake an ack */ + register SeqNum seq = SEQ_ADD(tpcb, tpcb->tp_snduna, 1); + + IFTRACE(D_DATA) + tptrace(TPPTmisc, "FAKE ACK seq cdt 1", + seq, 0,0,0); + ENDTRACE + IFDEBUG(D_DATA) + printf("FAKE ACK seq 0x%x cdt 1\n", seq ); + ENDDEBUG + E.ATTR(AK_TPDU).e_cdt = 1; + E.ATTR(AK_TPDU).e_seq = seq; + E.ATTR(AK_TPDU).e_subseq = 0; + E.ATTR(AK_TPDU).e_fcc_present = 0; + error = DoEvent(AK_TPDU); + if( error ) { + tpcb->tp_sock->so_error = error; + } + } /* else ignore it */ + } + break; + case PRC_ROUTEDEAD: + if (tpcb && tpcb->tp_class == TP_CLASS_0) { + tpiso_reset(isop); + break; + } /* else drop through */ + default: + (void) tpclnp_ctlinput(cmd, siso); + break; + } + return 0; +} + +/* + * CALLED FROM: + * cons's intr routine + * FUNCTION and ARGUMENTS: + * Take a packet (m) from cons, pullup m as required by tp, + * ignore the socket argument, and call tp_input. + * No return value. + */ +ProtoHook +tpcons_input(m, faddr, laddr, channel) + struct mbuf *m; + struct sockaddr_iso *faddr, *laddr; + caddr_t channel; +{ + if( m == MNULL) + return 0; + + m = (struct mbuf *)tp_inputprep(m); + + IFDEBUG(D_TPINPUT) + printf("tpcons_input before tp_input(m 0x%x)\n", m); + dump_buf( m, 12+ m->m_len); + ENDDEBUG + tp_input(m, faddr, laddr, channel, tpcons_output, 0); + return 0; +} + + +/* + * CALLED FROM: + * tp_emit() + * FUNCTION and ARGUMENTS: + * Take a packet(m0) from tp and package it so that cons will accept it. + * This means filling in a few of the fields. + * inp is the isopcb structure; datalen is the length of the data in the + * mbuf string m0. + * RETURN VALUE: + * whatever (E*) is returned form the net layer output routine. + */ + +int +tpcons_output(isop, m0, datalen, nochksum) + struct isopcb *isop; + struct mbuf *m0; + int datalen; + int nochksum; +{ + register struct mbuf *m = m0; + int error; + + IFDEBUG(D_EMIT) + printf( + "tpcons_output(isop 0x%x, m 0x%x, len 0x%x socket 0x%x\n", + isop, m0, datalen, isop->isop_socket); + ENDDEBUG + if (m == MNULL) + return 0; + if ((m->m_flags & M_PKTHDR) == 0) { + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) + return ENOBUFS; + m->m_next = m0; + } + m->m_pkthdr.len = datalen; + if (isop->isop_chan == 0) { + /* got a restart maybe? */ + if ((isop->isop_chan = (caddr_t) pk_attach((struct socket *)0)) == 0) { + IFDEBUG(D_CCONS) + printf("tpcons_output: no pklcd\n"); + ENDDEBUG + error = ENOBUFS; + } + if (error = cons_connect(isop)) { + pk_disconnect((struct pklcd *)isop->isop_chan); + isop->isop_chan = 0; + IFDEBUG(D_CCONS) + printf("tpcons_output: can't reconnect\n"); + ENDDEBUG + } + } else { + error = pk_send(isop->isop_chan, m); + IncStat(ts_tpdu_sent); + } + return error; +} +/* + * CALLED FROM: + * tp_error_emit() + * FUNCTION and ARGUMENTS: + * Take a packet(m0) from tp and package it so that cons will accept it. + * chan is the cons channel to use; datalen is the length of the data in the + * mbuf string m0. + * RETURN VALUE: + * whatever (E*) is returned form the net layer output routine. + */ + +int +tpcons_dg_output(chan, m0, datalen) + caddr_t chan; + struct mbuf *m0; + int datalen; +{ + return tpcons_output(((struct pklcd *)chan)->lcd_upnext, m0, datalen, 0); +} +#endif /* TPCONS */ +#endif /* ISO */ diff --git a/sys/netiso/tp_driver.c b/sys/netiso/tp_driver.c new file mode 100644 index 0000000..586ef4e --- /dev/null +++ b/sys/netiso/tp_driver.c @@ -0,0 +1,999 @@ +/* $Header$ */ +/* $Source$ */ +#ifndef lint +static char *rcsid = "$Header/**/$"; +#endif lint +#define _XEBEC_PG static + +#include "tp_states.h" + +static struct act_ent { + int a_newstate; + int a_action; +} statetable[] = { {0,0}, +#include "tp_states.init" +}; + +/* @(#)tp.trans 8.1 (Berkeley) 6/10/93 */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/mbuf.h> +#include <sys/time.h> +#include <sys/errno.h> + +#include <netiso/tp_param.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> +#include <netiso/iso_errno.h> +#include <netiso/tp_seq.h> +#include <netiso/cons.h> + +#define DRIVERTRACE TPPTdriver +#define sbwakeup(sb) sowakeup(p->tp_sock, sb); +#define MCPY(d, w) (d ? m_copym(d, 0, (int)M_COPYALL, w): 0) + +static trick_hc = 1; + +int tp_emit(), + tp_goodack(), tp_goodXack(), + tp_stash() +; +void tp_indicate(), tp_getoptions(), + tp_soisdisconnecting(), tp_soisdisconnected(), + tp_recycle_tsuffix(), +#ifdef TP_DEBUG_TIMERS + tp_etimeout(), tp_euntimeout(), + tp_ctimeout(), tp_cuntimeout(), + tp_ctimeout_MIN(), +#endif + tp_freeref(), tp_detach(), + tp0_stash(), tp0_send(), + tp_netcmd(), tp_send() +; + +typedef struct tp_pcb tpcb_struct; + + + +typedef tpcb_struct tp_PCB_; + +#include "tp_events.h" + +_XEBEC_PG int _Xebec_action(a,e,p) +int a; +struct tp_event *e; +tp_PCB_ *p; +{ +switch(a) { +case -1: return tp_protocol_error(e,p); +case 0x1: + { + (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); + } + break; +case 0x2: + { +# ifdef TP_DEBUG + if( e->ev_number != AK_TPDU ) + printf("TPDU 0x%x in REFWAIT!!!!\n", e->ev_number); +# endif TP_DEBUG + } + break; +case 0x3: + { + /* oh, man is this grotesque or what? */ + (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq); + /* but it's necessary because this pseudo-ack may happen + * before the CC arrives, but we HAVE to adjust the + * snduna as a result of the ack, WHENEVER it arrives + */ + } + break; +case 0x4: + { + tp_detach(p); + } + break; +case 0x5: + { + p->tp_refstate = REF_OPEN; /* has timers ??? */ + } + break; +case 0x6: + { + IFTRACE(D_CONN) + tptrace(TPPTmisc, "CR datalen data", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("CR datalen 0x%x data 0x%x", e->ev_union.EV_CR_TPDU.e_datalen, e->ev_union.EV_CR_TPDU.e_data); + ENDDEBUG + p->tp_refstate = REF_OPEN; /* has timers */ + p->tp_fcredit = e->ev_union.EV_CR_TPDU.e_cdt; + + if (e->ev_union.EV_CR_TPDU.e_datalen > 0) { + /* n/a for class 0 */ + ASSERT(p->tp_Xrcv.sb_cc == 0); + sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CR_TPDU.e_data); + e->ev_union.EV_CR_TPDU.e_data = MNULL; + } + } + break; +case 0x7: + { + IncStat(ts_tp0_conn); + IFTRACE(D_CONN) + tptrace(TPPTmisc, "Confiming", p, 0,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("Confirming connection: p" ); + ENDDEBUG + soisconnected(p->tp_sock); + (void) tp_emit(CC_TPDU_type, p, 0,0, MNULL) ; + p->tp_fcredit = 1; + } + break; +case 0x8: + { + IncStat(ts_tp4_conn); /* even though not quite open */ + IFTRACE(D_CONN) + tptrace(TPPTmisc, "Confiming", p, 0,0,0); + ENDTRACE + IFDEBUG(D_CONN) + printf("Confirming connection: p" ); + ENDDEBUG + tp_getoptions(p); + soisconnecting(p->tp_sock); + if ((p->tp_rx_strat & TPRX_FASTSTART) && (p->tp_fcredit > 0)) + p->tp_cong_win = p->tp_fcredit * p->tp_l_tpdusize; + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); + } + break; +case 0x9: + { + IFDEBUG(D_CONN) + printf("event: CR_TPDU emit CC failed done " ); + ENDDEBUG + soisdisconnected(p->tp_sock); + tp_recycle_tsuffix(p); + tp_freeref(p->tp_lref); + tp_detach(p); + } + break; +case 0xa: + { + int error; + struct mbuf *data = MNULL; + + IFTRACE(D_CONN) + tptrace(TPPTmisc, "T_CONN_req flags ucddata", (int)p->tp_flags, + p->tp_ucddata, 0, 0); + ENDTRACE + data = MCPY(p->tp_ucddata, M_WAIT); + if (data) { + IFDEBUG(D_CONN) + printf("T_CONN_req.trans m_copy cc 0x%x\n", + p->tp_ucddata); + dump_mbuf(data, "sosnd @ T_CONN_req"); + ENDDEBUG + } + + if (error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) + return error; /* driver WON'T change state; will return error */ + + p->tp_refstate = REF_OPEN; /* has timers */ + if(p->tp_class != TP_CLASS_0) { + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); + } + } + break; +case 0xb: + { + sbflush(&p->tp_Xrcv); /* purge non-delivered data data */ + if (e->ev_union.EV_DR_TPDU.e_datalen > 0) { + sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_DR_TPDU.e_data); + e->ev_union.EV_DR_TPDU.e_data = MNULL; + } + if (p->tp_state == TP_OPEN) + tp_indicate(T_DISCONNECT, p, 0); + else { + int so_error = ECONNREFUSED; + if (e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_SESSION ^ TP_ERROR_MASK) && + e->ev_union.EV_DR_TPDU.e_reason != (E_TP_NO_CR_ON_NC ^ TP_ERROR_MASK) && + e->ev_union.EV_DR_TPDU.e_reason != (E_TP_REF_OVERFLOW ^ TP_ERROR_MASK)) + so_error = ECONNABORTED; + tp_indicate(T_DISCONNECT, p, so_error); + } + tp_soisdisconnected(p); + if (p->tp_class != TP_CLASS_0) { + if (p->tp_state == TP_OPEN ) { + tp_euntimeout(p, TM_data_retrans); /* all */ + tp_cuntimeout(p, TM_retrans); + tp_cuntimeout(p, TM_inact); + tp_cuntimeout(p, TM_sendack); + p->tp_flags &= ~TPF_DELACK; + } + tp_cuntimeout(p, TM_retrans); + if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) + (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); + } + } + break; +case 0xc: + { + if( e->ev_union.EV_DR_TPDU.e_sref != 0 ) + (void) tp_emit(DC_TPDU_type, p, 0, 0, MNULL); + /* reference timer already set - reset it to be safe (???) */ + tp_euntimeout(p, TM_reference); /* all */ + tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); + } + break; +case 0xd: + { + tp_cuntimeout(p, TM_retrans); + tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); + tp_soisdisconnected(p); + } + break; +case 0xe: + { + tp_cuntimeout(p, TM_retrans); + tp_soisdisconnected(p); + } + break; +case 0xf: + { + tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); + tp_cuntimeout(p, TM_retrans); + tp_soisdisconnected(p); + } + break; +case 0x10: + { + tp_cuntimeout(p, TM_retrans); + tp_soisdisconnected(p); + } + break; +case 0x11: + { /* don't ask me why we have to do this - spec says so */ + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NO_SESSION, MNULL); + /* don't bother with retransmissions of the DR */ + } + break; +case 0x12: + { + tp_soisdisconnecting(p->tp_sock); + tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); + tp_soisdisconnected(p); + tp_netcmd( p, CONN_CLOSE ); + } + break; +case 0x13: + { + if (p->tp_state == TP_OPEN) { + tp_euntimeout(p, TM_data_retrans); /* all */ + tp_cuntimeout(p, TM_inact); + tp_cuntimeout(p, TM_sendack); + } + tp_soisdisconnecting(p->tp_sock); + tp_indicate(ER_TPDU, p, e->ev_union.EV_ER_TPDU.e_reason); + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_PROTO_ERR, MNULL); + } + break; +case 0x14: + { + tp_cuntimeout(p, TM_retrans); + IncStat(ts_tp0_conn); + p->tp_fcredit = 1; + soisconnected(p->tp_sock); + } + break; +case 0x15: + { + IFDEBUG(D_CONN) + printf("trans: CC_TPDU in CRSENT state flags 0x%x\n", + (int)p->tp_flags); + ENDDEBUG + IncStat(ts_tp4_conn); + p->tp_fref = e->ev_union.EV_CC_TPDU.e_sref; + p->tp_fcredit = e->ev_union.EV_CC_TPDU.e_cdt; + if ((p->tp_rx_strat & TPRX_FASTSTART) && (e->ev_union.EV_CC_TPDU.e_cdt > 0)) + p->tp_cong_win = e->ev_union.EV_CC_TPDU.e_cdt * p->tp_l_tpdusize; + tp_getoptions(p); + tp_cuntimeout(p, TM_retrans); + if (p->tp_ucddata) { + IFDEBUG(D_CONN) + printf("dropping user connect data cc 0x%x\n", + p->tp_ucddata->m_len); + ENDDEBUG + m_freem(p->tp_ucddata); + p->tp_ucddata = 0; + } + soisconnected(p->tp_sock); + if (e->ev_union.EV_CC_TPDU.e_datalen > 0) { + ASSERT(p->tp_Xrcv.sb_cc == 0); /* should be empty */ + sbappendrecord(&p->tp_Xrcv, e->ev_union.EV_CC_TPDU.e_data); + e->ev_union.EV_CC_TPDU.e_data = MNULL; + } + + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + break; +case 0x16: + { + struct mbuf *data = MNULL; + int error; + + IncStat(ts_retrans_cr); + p->tp_cong_win = 1 * p->tp_l_tpdusize; + data = MCPY(p->tp_ucddata, M_NOWAIT); + if(p->tp_ucddata) { + IFDEBUG(D_CONN) + printf("TM_retrans.trans m_copy cc 0x%x\n", data); + dump_mbuf(p->tp_ucddata, "sosnd @ TM_retrans"); + ENDDEBUG + if( data == MNULL ) + return ENOBUFS; + } + + p->tp_retrans --; + if( error = tp_emit(CR_TPDU_type, p, 0, 0, data) ) { + p->tp_sock->so_error = error; + } + tp_ctimeout(p, TM_retrans, (int)p->tp_cr_ticks); + } + break; +case 0x17: + { + IncStat(ts_conn_gaveup); + p->tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, p, ETIMEDOUT); + tp_soisdisconnected(p); + } + break; +case 0x18: + { + int error; + struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); + + if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) { + p->tp_sock->so_error = error; + } + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); + } + break; +case 0x19: + { + int doack; + + /* + * Get rid of any confirm or connect data, so that if we + * crash or close, it isn't thought of as disconnect data. + */ + if (p->tp_ucddata) { + m_freem(p->tp_ucddata); + p->tp_ucddata = 0; + } + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + tp_cuntimeout(p, TM_retrans); + soisconnected(p->tp_sock); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + + /* see also next 2 transitions, if you make any changes */ + + doack = tp_stash(p, e); + IFDEBUG(D_DATA) + printf("tp_stash returns %d\n",doack); + ENDDEBUG + + if (doack) { + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); + tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); + } else + tp_ctimeout( p, TM_sendack, (int)p->tp_sendack_ticks); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } + break; +case 0x1a: + { + tp0_stash(p, e); + sbwakeup( &p->tp_sock->so_rcv ); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } + break; +case 0x1b: + { + int doack; /* tells if we must ack immediately */ + + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + sbwakeup( &p->tp_sock->so_rcv ); + + doack = tp_stash(p, e); + IFDEBUG(D_DATA) + printf("tp_stash returns %d\n",doack); + ENDDEBUG + + if(doack) + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); + else + tp_ctimeout_MIN( p, TM_sendack, (int)p->tp_sendack_ticks); + + IFDEBUG(D_DATA) + printf("after stash calling sbwakeup\n"); + ENDDEBUG + } + break; +case 0x1c: + { + IFTRACE(D_DATA) + tptrace(TPPTmisc, "NIW seq rcvnxt lcredit ", + e->ev_union.EV_DT_TPDU.e_seq, p->tp_rcvnxt, p->tp_lcredit, 0); + ENDTRACE + IncStat(ts_dt_niw); + m_freem(e->ev_union.EV_DT_TPDU.e_data); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL ); + } + break; +case 0x1d: + { + if (p->tp_ucddata) { + m_freem(p->tp_ucddata); + p->tp_ucddata = 0; + } + (void) tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq); + tp_cuntimeout(p, TM_retrans); + + soisconnected(p->tp_sock); + IFTRACE(D_CONN) + struct socket *so = p->tp_sock; + tptrace(TPPTmisc, + "called sosiconn: so so_state rcv.sb_sel rcv.sb_flags", + so, so->so_state, so->so_rcv.sb_sel, so->so_rcv.sb_flags); + tptrace(TPPTmisc, + "called sosiconn 2: so_qlen so_error so_rcv.sb_cc so_head", + so->so_qlen, so->so_error, so->so_rcv.sb_cc, so->so_head); + ENDTRACE + + tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + break; +case 0x1e: + { + if( p->tp_state == TP_AKWAIT ) { + if (p->tp_ucddata) { + m_freem(p->tp_ucddata); + p->tp_ucddata = 0; + } + tp_cuntimeout(p, TM_retrans); + soisconnected(p->tp_sock); + tp_ctimeout(p, TM_sendack, (int)p->tp_keepalive_ticks); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD tpdu accepted Xrcvnxt, e_seq datalen m_len\n", + p->tp_Xrcvnxt,e->ev_union.EV_XPD_TPDU.e_seq, e->ev_union.EV_XPD_TPDU.e_datalen, e->ev_union.EV_XPD_TPDU.e_data->m_len); + ENDTRACE + + p->tp_sock->so_state |= SS_RCVATMARK; + e->ev_union.EV_XPD_TPDU.e_data->m_flags |= M_EOR; + sbinsertoob(&p->tp_Xrcv, e->ev_union.EV_XPD_TPDU.e_data); + IFDEBUG(D_XPD) + dump_mbuf(e->ev_union.EV_XPD_TPDU.e_data, "XPD TPDU: tp_Xrcv"); + ENDDEBUG + tp_indicate(T_XDATA, p, 0); + sbwakeup( &p->tp_Xrcv ); + + (void) tp_emit(XAK_TPDU_type, p, p->tp_Xrcvnxt, 0, MNULL); + SEQ_INC(p, p->tp_Xrcvnxt); + } + break; +case 0x1f: + { + if( p->tp_Xrcv.sb_cc == 0 ) { + /* kludge for select(): */ + /* p->tp_sock->so_state &= ~SS_OOBAVAIL; */ + } + } + break; +case 0x20: + { + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD tpdu niw (Xrcvnxt, e_seq) or not cdt (cc)\n", + p->tp_Xrcvnxt, e->ev_union.EV_XPD_TPDU.e_seq, p->tp_Xrcv.sb_cc , 0); + ENDTRACE + if( p->tp_Xrcvnxt != e->ev_union.EV_XPD_TPDU.e_seq ) + IncStat(ts_xpd_niw); + if( p->tp_Xrcv.sb_cc ) { + /* might as well kick 'em again */ + tp_indicate(T_XDATA, p, 0); + IncStat(ts_xpd_dup); + } + m_freem(e->ev_union.EV_XPD_TPDU.e_data); + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + /* don't send an xack because the xak gives "last one received", not + * "next one i expect" (dumb) + */ + } + break; +case 0x21: + { + struct socket *so = p->tp_sock; + + /* detach from parent socket so it can finish closing */ + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp: T_DETACH"); + so->so_head = 0; + } + tp_soisdisconnecting(p->tp_sock); + tp_netcmd( p, CONN_CLOSE); + tp_soisdisconnected(p); + } + break; +case 0x22: + { + struct socket *so = p->tp_sock; + struct mbuf *data = MNULL; + + /* detach from parent socket so it can finish closing */ + if (so->so_head) { + if (!soqremque(so, 0) && !soqremque(so, 1)) + panic("tp: T_DETACH"); + so->so_head = 0; + } + if (p->tp_state != TP_CLOSING) { + tp_soisdisconnecting(p->tp_sock); + data = MCPY(p->tp_ucddata, M_NOWAIT); + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_NORMAL_DISC, data); + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + } + } + break; +case 0x23: + { + tp_soisdisconnecting(p->tp_sock); + tp_netcmd( p, CONN_CLOSE); + tp_soisdisconnected(p); + } + break; +case 0x24: + { + struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); + + if(p->tp_state == TP_OPEN) { + tp_euntimeout(p, TM_data_retrans); /* all */ + tp_cuntimeout(p, TM_inact); + tp_cuntimeout(p, TM_sendack); + p->tp_flags &= ~TPF_DELACK; + } + if (data) { + IFDEBUG(D_CONN) + printf("T_DISC_req.trans tp_ucddata 0x%x\n", + p->tp_ucddata); + dump_mbuf(data, "ucddata @ T_DISC_req"); + ENDDEBUG + } + tp_soisdisconnecting(p->tp_sock); + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + + if( trick_hc ) + return tp_emit(DR_TPDU_type, p, 0, e->ev_union.EV_T_DISC_req.e_reason, data); + } + break; +case 0x25: + { + int error; + struct mbuf *data = MCPY(p->tp_ucddata, M_WAIT); + + IncStat(ts_retrans_cc); + p->tp_retrans --; + p->tp_cong_win = 1 * p->tp_l_tpdusize; + + if( error = tp_emit(CC_TPDU_type, p, 0, 0, data) ) + p->tp_sock->so_error = error; + tp_ctimeout(p, TM_retrans, (int)p->tp_cc_ticks); + } + break; +case 0x26: + { + IncStat(ts_conn_gaveup); + tp_soisdisconnecting(p->tp_sock); + p->tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, p, ETIMEDOUT); + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST, MNULL); + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + } + break; +case 0x27: + { + tp_euntimeout(p, TM_data_retrans); /* all */ + tp_cuntimeout(p, TM_inact); + tp_cuntimeout(p, TM_sendack); + + IncStat(ts_conn_gaveup); + tp_soisdisconnecting(p->tp_sock); + p->tp_sock->so_error = ETIMEDOUT; + tp_indicate(T_DISCONNECT, p, ETIMEDOUT); + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_CONGEST_2, MNULL); + p->tp_retrans = p->tp_Nretrans; + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + } + break; +case 0x28: + { + p->tp_cong_win = 1 * p->tp_l_tpdusize; + /* resume XPD */ + if ( p->tp_Xsnd.sb_mb ) { + struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); + int shift; + + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD retrans: Xuna Xsndnxt sndnxt snduna", + p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, + p->tp_snduna); + ENDTRACE + IFDEBUG(D_XPD) + dump_mbuf(m, "XPD retrans emitting M"); + ENDDEBUG + IncStat(ts_retrans_xpd); + p->tp_retrans --; + shift = max(p->tp_Nretrans - p->tp_retrans, 6); + (void) tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); + tp_ctimeout(p, TM_retrans, ((int)p->tp_dt_ticks) << shift); + } + } + break; +case 0x29: + { + p->tp_rxtshift++; + (void) tp_data_retrans(p); + } + break; +case 0x2a: + { + p->tp_retrans --; + (void) tp_emit(DR_TPDU_type, p, 0, E_TP_DR_NO_REAS, MNULL); + IncStat(ts_retrans_dr); + tp_ctimeout(p, TM_retrans, (int)p->tp_dr_ticks); + } + break; +case 0x2b: + { + p->tp_sock->so_error = ETIMEDOUT; + p->tp_refstate = REF_FROZEN; + tp_recycle_tsuffix( p ); + tp_etimeout(p, TM_reference, (int)p->tp_refer_ticks); + } + break; +case 0x2c: + { + tp_freeref(p->tp_lref); + tp_detach(p); + } + break; +case 0x2d: + { + if( p->tp_class != TP_CLASS_0) { + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + if ( e->ev_number == CC_TPDU ) + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); + } + /* ignore it if class 0 - state tables are blank for this */ + } + break; +case 0x2e: + { + IFTRACE(D_DATA) + tptrace(TPPTmisc, "T_DATA_req sndnxt snduna fcredit, tpcb", + p->tp_sndnxt, p->tp_snduna, p->tp_fcredit, p); + ENDTRACE + + tp_send(p); + } + break; +case 0x2f: + { + int error = 0; + + /* resume XPD */ + if ( p->tp_Xsnd.sb_mb ) { + struct mbuf *m = m_copy(p->tp_Xsnd.sb_mb, 0, (int)p->tp_Xsnd.sb_cc); + /* m_copy doesn't preserve the m_xlink field, but at this pt. + * that doesn't matter + */ + + IFTRACE(D_XPD) + tptrace(TPPTmisc, "XPD req: Xuna Xsndnxt sndnxt snduna", + p->tp_Xuna, p->tp_Xsndnxt, p->tp_sndnxt, + p->tp_snduna); + ENDTRACE + IFDEBUG(D_XPD) + printf("T_XPD_req: sb_cc 0x%x\n", p->tp_Xsnd.sb_cc); + dump_mbuf(m, "XPD req emitting M"); + ENDDEBUG + error = + tp_emit(XPD_TPDU_type, p, p->tp_Xuna, 1, m); + p->tp_retrans = p->tp_Nretrans; + + tp_ctimeout(p, TM_retrans, (int)p->tp_rxtcur); + SEQ_INC(p, p->tp_Xsndnxt); + } + if(trick_hc) + return error; + } + break; +case 0x30: + { + struct sockbuf *sb = &p->tp_sock->so_snd; + + IFDEBUG(D_ACKRECV) + printf("GOOD ACK seq 0x%x cdt 0x%x\n", e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_cdt); + ENDDEBUG + if( p->tp_class != TP_CLASS_0) { + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + sbwakeup(sb); + IFDEBUG(D_ACKRECV) + printf("GOOD ACK new sndnxt 0x%x\n", p->tp_sndnxt); + ENDDEBUG + } + break; +case 0x31: + { + IFTRACE(D_ACKRECV) + tptrace(TPPTmisc, "BOGUS ACK fcc_present, tp_r_subseq e_subseq", + e->ev_union.EV_AK_TPDU.e_fcc_present, p->tp_r_subseq, e->ev_union.EV_AK_TPDU.e_subseq, 0); + ENDTRACE + if( p->tp_class != TP_CLASS_0 ) { + + if ( !e->ev_union.EV_AK_TPDU.e_fcc_present ) { + /* send ACK with FCC */ + IncStat( ts_ackreason[_ACK_FCC_] ); + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 1, MNULL); + } + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + } + break; +case 0x32: + { + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + tp_cuntimeout(p, TM_retrans); + + sbwakeup( &p->tp_sock->so_snd ); + + /* resume normal data */ + tp_send(p); + } + break; +case 0x33: + { + IFTRACE(D_ACKRECV) + tptrace(TPPTmisc, "BOGUS XACK eventtype ", e->ev_number, 0, 0,0); + ENDTRACE + if( p->tp_class != TP_CLASS_0 ) { + tp_ctimeout(p, TM_inact, (int)p->tp_inact_ticks); + } + } + break; +case 0x34: + { + int timo; + IFTRACE(D_TIMER) + tptrace(TPPTsendack, -1, p->tp_lcredit, p->tp_sent_uwe, + p->tp_sent_lcdt, 0); + ENDTRACE + IncPStat(p, tps_n_TMsendack); + (void) tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); + if (p->tp_fcredit == 0) { + if (p->tp_rxtshift < TP_MAXRXTSHIFT) + p->tp_rxtshift++; + timo = (p->tp_dt_ticks) << p->tp_rxtshift; + } else + timo = p->tp_sendack_ticks; + tp_ctimeout(p, TM_sendack, timo); + } + break; +case 0x35: + { + if (sbspace(&p->tp_sock->so_rcv) > 0) + tp0_openflow(p); + } + break; +case 0x36: + { + if( trick_hc ) { + SeqNum ack_thresh; + /* + * If the upper window edge has advanced a reasonable + * amount beyond what was known, send an ACK. + * A reasonable amount is 2 packets, unless the max window + * is only 1 or 2 packets, in which case we + * should send an ack for any advance in the upper window edge. + */ + LOCAL_CREDIT(p); + ack_thresh = SEQ_SUB(p, p->tp_lcredit + p->tp_rcvnxt, + (p->tp_maxlcredit > 2 ? 2 : 1)); + if (SEQ_GT(p, ack_thresh, p->tp_sent_uwe)) { + IncStat(ts_ackreason[_ACK_USRRCV_]); + p->tp_flags &= ~TPF_DELACK; + return tp_emit(AK_TPDU_type, p, p->tp_rcvnxt, 0, MNULL); + } + } + } + break; +case 0x37: + { + if(trick_hc) + return ECONNABORTED; + } + break; +case 0x38: + { + ASSERT( p->tp_state != TP_LISTENING ); + tp_indicate(T_DISCONNECT, p, ECONNRESET); + tp_soisdisconnected(p); + } + break; + } +return 0; +} + +_XEBEC_PG int +_Xebec_index( e,p ) + struct tp_event *e; + tp_PCB_ *p; +{ +switch( (e->ev_number<<4)+(p->tp_state) ) { +case 0x12: + if ( p->tp_retrans > 0 ) return 0x1e; + else return 0x1f; +case 0x13: + if ( p->tp_retrans > 0 ) return 0x2f; + else return 0x30; +case 0x14: + if ( p->tp_retrans > 0 ) return 0x32; + else return 0x31; +case 0x15: + if ( p->tp_retrans > 0 ) return 0x34; + else return 0x35; +case 0x54: + if (p->tp_rxtshift < TP_NRETRANS) return 0x33; + else return 0x31; +case 0x64: + if (p->tp_class == TP_CLASS_0) return 0x1a; + else return 0x1b; +case 0x77: + if ( p->tp_class == TP_CLASS_0) return 0xd; + else return 0xe; +case 0x86: + if ( e->ev_union.EV_DR_TPDU.e_sref != 0 ) return 0x2; + else return 0x3; +case 0xa2: + if (p->tp_class == TP_CLASS_0) return 0x1c; + else return 0x1d; +case 0xb2: + if (p->tp_class == TP_CLASS_0) return 0x5; + else return 0x0; +case 0xb4: + if ( tp_goodack(p, e->ev_union.EV_AK_TPDU.e_cdt, e->ev_union.EV_AK_TPDU.e_seq, e->ev_union.EV_AK_TPDU.e_subseq) ) return 0x3a; + else return 0x3b; +case 0xc3: + if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, + p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x21; + else return 0x24; +case 0xc4: + if ( p->tp_class == TP_CLASS_0 ) return 0x22; + else if ( IN_RWINDOW( p, e->ev_union.EV_DT_TPDU.e_seq, + p->tp_rcvnxt, SEQ(p, p->tp_rcvnxt + p->tp_lcredit)) ) return 0x23; + else return 0x25; +case 0xd3: + if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; + else return 0x2a; +case 0xd4: + if (p->tp_Xrcvnxt == e->ev_union.EV_XPD_TPDU.e_seq) return 0x27; + else return 0x29; +case 0xe4: + if ( tp_goodXack(p, e->ev_union.EV_XAK_TPDU.e_seq) ) return 0x3c; + else return 0x3d; +case 0x102: + if ( p->tp_class == TP_CLASS_0 ) return 0x2d; + else return 0x2e; +case 0x104: + if ( p->tp_class == TP_CLASS_0 ) return 0x2d; + else return 0x2e; +case 0x144: + if (p->tp_class == TP_CLASS_0) return 0x3f; + else return 0x40; +case 0x162: + if (p->tp_class == TP_CLASS_0) return 0x2b; + else return 0x2c; +case 0x172: + if ( p->tp_class != TP_CLASS_4 ) return 0x42; + else return 0x46; +case 0x174: + if ( p->tp_class != TP_CLASS_4 ) return 0x42; + else return 0x47; +case 0x177: + if ( p->tp_class != TP_CLASS_4 ) return 0x42; + else return 0x43; +case 0x188: + if ( p->tp_class == TP_CLASS_0 ) return 0xf; + else if (tp_emit(CC_TPDU_type, p, 0,0, MCPY(p->tp_ucddata, M_NOWAIT)) == 0) return 0x10; + else return 0x11; +default: return 0; +} /* end switch */ +} /* _Xebec_index() */ +static int inx[26][9] = { {0,0,0,0,0,0,0,0,0,}, + {0x0,0x0,0x0,0x0,0x31,0x0,0x0,0x0,0x0, }, + {0x0,0x0,-1,-1,-1,-1,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x0,0x0,0x36,0x0,0x0, }, + {0x0,0x0,0x0,0x0,-1,0x0,0x0,0x0,0x0, }, + {0x0,0x7,0x15,0x1b,-1,0x17,0x3,0xa,0x0, }, + {0x0,0x19,0x6,0x20,0x37,0x8,0x3,-1,0x0, }, + {0x0,0x14,0x13,0x13,0x13,0x16,-1,0xa,0x0, }, + {0x0,0x7,0x6,0x1,0x9,0x18,0x3,0xa,0x0, }, + {0x0,0x19,-1,0x1,0x37,0x8,0x3,0xa,0x0, }, + {0x0,0x7,-1,0x26,-1,0x8,0x3,0xa,0x0, }, + {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, + {0x0,0x7,0x6,-1,-1,0x8,0x3,0xa,0x0, }, + {0x0,0x7,0x6,0x1,-1,0x8,0x3,0xa,0x0, }, + {0x0,0x12,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, + {0x0,0x0,-1,0x2e,-1,0x0,0x4,0x0,0x2e, }, + {0x0,0xb,0x0,0x0,0x0,0x0,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x38,0x0,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x39,0x0,0x0,0x0,0x0, }, + {0x0,0x0,0x0,0x0,-1,0x0,0x41,0x0,0x0, }, + {0x0,0x0,0x0,0x0,0x28,0x0,0x41,0x0,0x0, }, + {0x0,0xc,-1,0x2c,0x0,0x2c,0x4,0xc,0x2c, }, + {0x0,0x49,-1,0x45,-1,0x44,0x48,-1,0x0, }, + {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,-1, }, +}; +tp_driver(p, e) +register tp_PCB_ *p; +register struct tp_event *e; +{ + register int index, error=0; + struct act_ent *a; + static struct act_ent erroraction = {0,-1}; + + index = inx[1 + e->ev_number][p->tp_state]; + if(index<0) index=_Xebec_index(e, p); + if (index==0) { + a = &erroraction; + } else + a = &statetable[index]; + + if(a->a_action) + error = _Xebec_action( a->a_action, e, p ); + IFTRACE(D_DRIVER) + tptrace(DRIVERTRACE, a->a_newstate, p->tp_state, e->ev_number, a->a_action, 0); + ENDTRACE + if(error==0) + p->tp_state = a->a_newstate; + return error; +} diff --git a/sys/netiso/tp_emit.c b/sys/netiso/tp_emit.c new file mode 100644 index 0000000..16ed5bc --- /dev/null +++ b/sys/netiso/tp_emit.c @@ -0,0 +1,996 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_emit.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_emit.c,v 5.5 88/11/18 17:27:20 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_emit.c,v $ + * + * This file contains tp_emit() and tp_error_emit(), which + * form TPDUs and hand them to ip. + * They take data in the form of mbuf chain, allocate mbufs as + * necessary for headers, and set the fields as appropriate from + * information found in the tpcb and net-level pcb. + * + * The worst thing about this code is adding the variable-length + * options on a machine that requires alignment for any memory access + * that isn't of size 1. See the macro ADDOPTION() below. + * + * We don't do any concatenation. (There's a kludge to test the + * basic mechanism of separation under the 'w' tpdebug option, that's all.) + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <netiso/iso.h> +#include <netiso/iso_pcb.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_param.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_meas.h> +#include <netiso/tp_seq.h> +#include <netiso/iso_errno.h> + +#include <net/if.h> +#ifdef TRUE +#undef FALSE +#undef TRUE +#endif +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> + +void iso_gen_csum(); + + +/* Here is a mighty kludge. The token ring misorders packets if you + * fire them at it too fast, and TP sans checksum is "too fast", so + * we have introduced a delay when checksumming isn't used. + */ +char tp_delay = 0x00; /* delay to keep token ring from blowing it */ + +/* + * NAME: tp_emit() + * + * CALLED FROM: tp.trans and from tp_sbsend() + * + * FUNCTION and ARGUMENTS: + * Emits one tpdu of the type (dutype), of the format appropriate + * to the connection described by the pcb (tpcb), with sequence + * number (seq) (where appropriate), end-of-tsdu bit (eot) where + * appropriate, and with the data in the mbuf chain (data). + * For DR and ER tpdus, the argument (eot) is + * the reason for issuing the tpdu rather than an end-of-tsdu indicator. + * + * RETURNS: + * 0 OK + * ENOBUFS + * E* returned from net layer output rtn + * + * SIDE EFFECTS: + * + * NOTES: + * + * WE ASSUME that the tp header + all options will fit in ONE mbuf. + * If mbufs are 256 this will most likely be true, but if they are 128 it's + * possible that they won't. + * If you used every option on the CR + max. user data you'd overrun + * 112 but unless you used > 115 bytes for the security + * parameter, it would fit in a 256-byte mbuf (240 bytes for the header) + * We don't support the security parameter, so this isn't a problem. + * If security is added, we ought to remove this assumption. + * + * We do not implement the flow control confirmation "element of procedure". + * A) it should not affect interoperability, + * B) it should not be necessary - the protocol will eventually + * straighten things out w/o FCC, as long as we don't have severely + * mismatched keepalive and inactivity timers, and + * C) it appears not to be REQUIRED, and + * D) it's incredibly grotesque, and no doubt will lengthen a few + * critical paths. + * HOWEVER, we're thinking about putting it in anyway, for + * completeness, just like we did with ack subsequencing. + */ + +int +tp_emit(dutype, tpcb, seq, eot, data) + int dutype; + struct tp_pcb *tpcb; + SeqNum seq; + u_int eot; + struct mbuf *data; +{ + register struct tpdu *hdr; + register struct mbuf *m; + int csum_offset=0; + int datalen = 0; + int error = 0; + SeqNum olduwe; + int acking_ooo; + + /* NOTE: + * here we treat tpdu_li as if it DID include the li field, up until + * the end, at which time we subtract 1 + * THis is because if we subtract 1 right away, we end up adding + * one every time we add an option. + */ + IFDEBUG(D_EMIT) + printf( + "tp_emit dutype 0x%x, tpcb 0x%x, eot 0x%x, seq 0x%x, data 0x%x", + dutype, tpcb, eot, seq, data); + ENDDEBUG + + if (dutype == CR_TPDU || dutype == CC_TPDU) { + m = (struct mbuf *) malloc((u_long)256, M_MBUF, M_DONTWAIT); + if (m) { + m->m_type = TPMT_TPHDR; + mbstat.m_mtypes[TPMT_TPHDR]++; + m->m_next = MNULL; + m->m_nextpkt = MNULL; + m->m_data = m->m_pktdat; + m->m_flags = M_PKTHDR; + } + } else { + MGETHDR(m, M_DONTWAIT, TPMT_TPHDR); + } + m->m_data += max_hdr; + if (m == NULL) { + if(data != (struct mbuf *)0) + m_freem(data); + error = ENOBUFS; + goto done; + } + m->m_len = sizeof(struct tpdu); + m->m_act = MNULL; + + hdr = mtod(m, struct tpdu *); + bzero((caddr_t)hdr, sizeof(struct tpdu)); + + { + int tp_headersize(); + + hdr->tpdu_type = dutype; + hdr->tpdu_li = tp_headersize(dutype, tpcb); + /* + * class 0 doesn't use this for DT + * it'll just get overwritten below + */ + hdr->tpdu_dref = htons(tpcb->tp_fref); + if( tpcb->tp_use_checksum || + (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4) )) { + csum_offset = hdr->tpdu_li + 2; /* DOESN'T include csum */ + ADDOPTION(TPP_checksum, hdr, 2, eot /* dummy arg */); + IFDEBUG(D_CHKSUM) + printf( + "tp_emit: csum_offset 0x%x, hdr->tpdu_li 0x%x\n", + csum_offset, hdr->tpdu_li); + ENDDEBUG + } + /* + * VARIABLE PARTS... + */ + switch( dutype ) { + + case CR_TPDU_type: + hdr->tpdu_CRdref_0 = 0; /* must be zero */ + case CC_TPDU_type: + if (!tpcb->tp_cebit_off) { + tpcb->tp_win_recv = tp_start_win << 8; + LOCAL_CREDIT(tpcb); + CONG_INIT_SAMPLE(tpcb); + } else + LOCAL_CREDIT(tpcb); + +/* Case CC_TPDU_type used to be here */ + { + u_char x; + + hdr->tpdu_CCsref = htons(tpcb->tp_lref); /* same as CRsref */ + + if( tpcb->tp_class > TP_CLASS_1 ) { + tpcb->tp_sent_uwe = tpcb->tp_lcredit -1; + tpcb->tp_sent_rcvnxt = 1; + tpcb->tp_sent_lcdt = tpcb->tp_lcredit; + hdr->tpdu_cdt = tpcb->tp_lcredit; + } else { +#ifdef TPCONS + if (tpcb->tp_netservice == ISO_CONS) { + struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + struct pklcd *lcp = (struct pklcd *)(isop->isop_chan); + lcp->lcd_flags &= ~X25_DG_CIRCUIT; + } +#endif + hdr->tpdu_cdt = 0; + } + hdr->tpdu_CCclass = tp_mask_to_num(tpcb->tp_class); + hdr->tpdu_CCoptions = + (tpcb->tp_xtd_format? TPO_XTD_FMT:0) | + (tpcb->tp_use_efc? TPO_USE_EFC:0); + + IFPERF(tpcb) + u_char perf_meas = tpcb->tp_perf_on; + ADDOPTION(TPP_perf_meas, hdr, sizeof(perf_meas), perf_meas); + ENDPERF + + if( dutype == CR_TPDU_type ) { + IncStat(ts_CR_sent); + + ASSERT( tpcb->tp_lsuffixlen > 0 ); + ASSERT( tpcb->tp_fsuffixlen > 0 ); + + ADDOPTION(TPP_calling_sufx, hdr, + tpcb->tp_lsuffixlen, tpcb->tp_lsuffix[0]); + ADDOPTION(TPP_called_sufx, hdr, + tpcb->tp_fsuffixlen, tpcb->tp_fsuffix[0]); + } else { + IncStat(ts_CC_sent); + } + + ADDOPTION(TPP_tpdu_size, hdr, + sizeof(tpcb->tp_tpdusize), tpcb->tp_tpdusize); + + if (tpcb->tp_class != TP_CLASS_0) { + short millisec = 500*(tpcb->tp_sendack_ticks); + + millisec = htons(millisec); + ADDOPTION(TPP_acktime, hdr, sizeof(short), millisec); + + x = (tpcb->tp_use_nxpd? TPAO_USE_NXPD: 0) + | (tpcb->tp_use_rcc? TPAO_USE_RCC : 0) + | (tpcb->tp_use_checksum?0: TPAO_NO_CSUM) + | (tpcb->tp_xpd_service? TPAO_USE_TXPD: 0); + ADDOPTION(TPP_addl_opt, hdr, 1, x); + + if ((tpcb->tp_l_tpdusize ^ (1 << tpcb->tp_tpdusize)) != 0) { + u_short size_s = tpcb->tp_l_tpdusize >> 7; + u_char size_c = size_s; + ASSERT(tpcb->tp_l_tpdusize < 65536 * 128); + if (dutype == CR_TPDU_type) + tpcb->tp_ptpdusize = size_s; + if (size_s < 256) { + ADDOPTION(TPP_ptpdu_size, hdr, 1, size_c); + } else { + size_s = htons(size_s); + ADDOPTION(TPP_ptpdu_size, hdr, 2, size_s); + } + } + } + + if( (dutype == CR_TPDU_type) && (tpcb->tp_class != TP_CLASS_0)){ + + ASSERT( 1 == sizeof(tpcb->tp_vers) ); + ADDOPTION(TPP_vers, hdr, 1, tpcb->tp_vers); + + /* for each alt protocol class x, + * x = x<<4; + * option = concat(option, x); + * Well, for now we only have TP0 for an + * alternative so... this is easy. + * + * HOWEVER... There should be NO alt protocol + * class over CLNS. Need to see if the route suggests + * CONS, and iff so add alt class. + */ + x = 0; + ADDOPTION(TPP_alt_class, hdr, 1, x); + } + + if( hdr->tpdu_li > MLEN) + panic("tp_emit CR/CC"); + } + break; + + case DR_TPDU_type: + if( hdr->tpdu_DRdref == 0 ) { + /* don't issue the DR */ + goto done; + } + hdr->tpdu_cdt = 0; + hdr->tpdu_DRsref = htons(tpcb->tp_lref); + hdr->tpdu_DRreason = (u_char)eot; /* WHICH BYTE OF THIS??? */ + + /* forget the add'l information variable part */ + IncStat(ts_DR_sent); + break; + + case DC_TPDU_type: /* not used in class 0 */ + ASSERT( tpcb->tp_class != TP_CLASS_0); + hdr->tpdu_DCsref = htons(tpcb->tp_lref); + hdr->tpdu_cdt = 0; + data = (struct mbuf *)0; + IncStat(ts_DC_sent); + break; + + case XAK_TPDU_type: /* xak not used in class 0 */ + ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ + hdr->tpdu_cdt = 0; + + IFTRACE(D_XPD) + tptraceTPCB(TPPTXack, seq, 0, 0, 0, 0); + ENDTRACE + data = (struct mbuf *)0; + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seq = seq; + seqeotX.s_eot = 1; + hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); +#else + hdr->tpdu_XAKseqX = seq; +#endif /* BYTE_ORDER */ + } else { + hdr->tpdu_XAKseq = seq; + } + IncStat(ts_XAK_sent); + IncPStat(tpcb, tps_XAK_sent); + break; + + case XPD_TPDU_type: /* xpd not used in class 0 */ + ASSERT( tpcb->tp_class != TP_CLASS_0); /* fall through */ + hdr->tpdu_cdt = 0; + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seq = seq; + seqeotX.s_eot = 1; + hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); +#else + hdr->tpdu_XPDseqX = seq; + hdr->tpdu_XPDeotX = 1; /* always 1 for XPD tpdu */ +#endif /* BYTE_ORDER */ + } else { + hdr->tpdu_XPDseq = seq; + hdr->tpdu_XPDeot = 1; /* always 1 for XPD tpdu */ + } + IncStat(ts_XPD_sent); + IncPStat(tpcb, tps_XPD_sent); + + /* kludge to test the input size checking */ + IFDEBUG(D_SIZE_CHECK) + /*if(data->m_len <= 16 && data->m_off < (MLEN-18) ) { + printf("Sending too much data on XPD: 18 bytes\n"); + data->m_len = 18; + }*/ + ENDDEBUG + break; + + case DT_TPDU_type: + hdr->tpdu_cdt = 0; + IFTRACE(D_DATA) + tptraceTPCB(TPPTmisc, "emit DT: eot seq tpdu_li", eot, seq, + hdr->tpdu_li, 0); + ENDTRACE + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seq = seq; + seqeotX.s_eot = eot; + hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); +#else + hdr->tpdu_DTseqX = seq; + hdr->tpdu_DTeotX = eot; +#endif /* BYTE_ORDER */ + } else if (tpcb->tp_class == TP_CLASS_0) { + IFDEBUG(D_EMIT) + printf("DT tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); + dump_buf( hdr, hdr->tpdu_li + 1 ); + ENDDEBUG + ((struct tp0du *)hdr)->tp0du_eot = eot; + ((struct tp0du *)hdr)->tp0du_mbz = 0; + IFDEBUG(D_EMIT) + printf("DT 2 tpdu: class 0 m 0x%x hdr 0x%x\n", m, hdr); + dump_buf( hdr, hdr->tpdu_li + 1 ); + ENDDEBUG + } else { + hdr->tpdu_DTseq = seq; + hdr->tpdu_DTeot = eot; + } + if(eot) { + IncStat(ts_EOT_sent); + } + IncStat(ts_DT_sent); + IncPStat(tpcb, tps_DT_sent); + break; + + case AK_TPDU_type:/* ak not used in class 0 */ + ASSERT( tpcb->tp_class != TP_CLASS_0); + data = (struct mbuf *)0; + olduwe = tpcb->tp_sent_uwe; + + if (seq != tpcb->tp_sent_rcvnxt || tpcb->tp_rsycnt == 0) { + LOCAL_CREDIT( tpcb ); + tpcb->tp_sent_uwe = + SEQ(tpcb,tpcb->tp_rcvnxt + tpcb->tp_lcredit -1); + tpcb->tp_sent_lcdt = tpcb->tp_lcredit; + acking_ooo = 0; + } else + acking_ooo = 1; + + IFDEBUG(D_RENEG) + /* occasionally fake a reneging so + you can test subsequencing */ + if( olduwe & 0x1 ) { + tpcb->tp_reneged = 1; + IncStat(ts_ldebug); + } + ENDDEBUG + /* Are we about to reneg on credit? + * When might we do so? + * a) when using optimistic credit (which we no longer do). + * b) when drain() gets implemented (not in the plans). + * c) when D_RENEG is on. + * d) when DEC BIT response is implemented. + * (not- when we do this, we'll need to implement flow control + * confirmation) + */ + if( SEQ_LT(tpcb, tpcb->tp_sent_uwe, olduwe) ) { + tpcb->tp_reneged = 1; + IncStat(ts_lcdt_reduced); + IFTRACE(D_CREDIT) + tptraceTPCB(TPPTmisc, + "RENEG: olduwe newuwe lcredit rcvnxt", + olduwe, + tpcb->tp_sent_uwe, tpcb->tp_lcredit, + tpcb->tp_rcvnxt); + ENDTRACE + } + IFPERF(tpcb) + /* new lwe is less than old uwe means we're + * acking before we received a whole window full + */ + if( SEQ_LT( tpcb, tpcb->tp_rcvnxt, olduwe) ) { + /* tmp1 = number of pkts fewer than the full window */ + register int tmp1 = + (int) SEQ_SUB( tpcb, olduwe, tpcb->tp_rcvnxt); + + if(tmp1 > TP_PM_MAX) + tmp1 = TP_PM_MAX; + IncPStat( tpcb, tps_ack_early[tmp1] ); + + /* tmp1 = amt of new cdt we're advertising */ + tmp1 = SEQ_SUB( tpcb, seq, tpcb->tp_sent_rcvnxt); + if(tmp1 > TP_PM_MAX ) + tmp1 = TP_PM_MAX; + + IncPStat( tpcb, + tps_cdt_acked [ tmp1 ] + [ ((tpcb->tp_lcredit > TP_PM_MAX)? + TP_PM_MAX:tpcb->tp_lcredit) ] ); + + } + ENDPERF + + IFTRACE(D_ACKSEND) + tptraceTPCB(TPPTack, seq, tpcb->tp_lcredit, tpcb->tp_sent_uwe, + tpcb->tp_r_subseq, 0); + ENDTRACE + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seq = seq; + seqeotX.s_eot = 0; + hdr->tpdu_seqeotX = htonl(seqeotX.s_seqeot); + hdr->tpdu_AKcdtX = htons(tpcb->tp_lcredit); +#else + hdr->tpdu_cdt = 0; + hdr->tpdu_AKseqX = seq; + hdr->tpdu_AKcdtX = tpcb->tp_lcredit; +#endif /* BYTE_ORDER */ + } else { + hdr->tpdu_AKseq = seq; + hdr->tpdu_AKcdt = tpcb->tp_lcredit; + } + if ((tpcb->tp_class == TP_CLASS_4) && + (tpcb->tp_reneged || acking_ooo)) { + /* + * Ack subsequence parameter req'd if WE reneged on + * credit offered. (ISO 8073, 12.2.3.8.2, p. 74) + */ + IFDEBUG(D_RENEG) + printf("Adding subseq 0x%x\n", tpcb->tp_s_subseq); + ENDDEBUG + tpcb->tp_s_subseq++; + /* + * add tmp subseq and do a htons on it. + */ + ADDOPTION(TPP_subseq, hdr, + sizeof(tpcb->tp_s_subseq), tpcb->tp_s_subseq); + } else + tpcb->tp_s_subseq = 0; + + if ( tpcb->tp_sendfcc || eot ) /* overloaded to mean SEND FCC */ { + /* + * Rules for sending FCC ("should" send when) : + * %a) received an ack from peer with NO NEWS whatsoever, + * and it did not contain an FCC + * b) received an ack from peer that opens its closed window. + * c) received an ack from peer after it reneged on its + * offered credit, AND this ack raises UWE but LWE is same + * and below UWE at time of reneging (reduction) + * Now, ISO 8073 12.2.3.8.3 says + * that a retransmitted AK shall not contain the FCC + * parameter. Now, how the hell you tell the difference + * between a retransmitted ack and an ack that's sent in + * response to a received ack, I don't know, because without + * any local activity, and w/o any received DTs, they + * will contain exactly the same credit/seq# information. + * Anyway, given that the "retransmission of acks" + * procedure (ISO 8073 12.2.3.8.3) is optional, and we + * don't do it (although the peer can't tell that), we + * ignore this last rule. + * + * We send FCC for reasons a) and b) only. + * To add reason c) would require a ridiculous amount of state. + * + */ + u_short bogus[4]; /* lwe(32), subseq(16), cdt(16) */ + SeqNum lwe; + u_short subseq, fcredit; + + tpcb->tp_sendfcc = 0; + + lwe = (SeqNum) htonl(tpcb->tp_snduna); + subseq = htons(tpcb->tp_r_subseq); + fcredit = htons(tpcb->tp_fcredit); + + bcopy((caddr_t) &lwe, (caddr_t)&bogus[0], sizeof(SeqNum)); + bcopy((caddr_t) &subseq, (caddr_t)&bogus[2], sizeof(u_short)); + bcopy((caddr_t) &fcredit, (caddr_t)&bogus[3], sizeof(u_short)); + + IFTRACE(D_ACKSEND) + tptraceTPCB(TPPTmisc, + "emit w/FCC: snduna r_subseq fcredit", + tpcb->tp_snduna, tpcb->tp_r_subseq, + tpcb->tp_fcredit, 0); + ENDTRACE + + IFDEBUG(D_ACKSEND) + printf("Calling ADDOPTION 0x%x, 0x%x, 0x%x,0x%x\n", + TPP_flow_cntl_conf, + hdr, sizeof(bogus), bogus[0]); + ENDDEBUG + ADDOPTION(TPP_flow_cntl_conf, hdr, sizeof(bogus), bogus[0]); + IFDEBUG(D_ACKSEND) + printf("after ADDOPTION hdr 0x%x hdr->tpdu_li 0x%x\n", + hdr, hdr->tpdu_li); + printf( + "after ADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", + csum_offset, hdr->tpdu_li); + ENDDEBUG + + } + tpcb->tp_reneged = 0; + tpcb->tp_sent_rcvnxt = seq; + if (tpcb->tp_fcredit == 0) { + int timo = tpcb->tp_keepalive_ticks; + if (tpcb->tp_rxtshift < TP_MAXRXTSHIFT) + tpcb->tp_rxtshift++; + timo = min(timo, ((int)tpcb->tp_dt_ticks) << tpcb->tp_rxtshift); + tp_ctimeout(tpcb, TM_sendack, timo); + } else + tp_ctimeout(tpcb, TM_sendack, tpcb->tp_keepalive_ticks); + IncStat(ts_AK_sent); + IncPStat(tpcb, tps_AK_sent); + IFDEBUG(D_ACKSEND) + printf( + "2 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", + csum_offset, hdr->tpdu_li); + ENDDEBUG + break; + + case ER_TPDU_type: + hdr->tpdu_ERreason = eot; + hdr->tpdu_cdt = 0; + /* no user data */ + data = (struct mbuf *)0; + IncStat(ts_ER_sent); + break; + } + + } + ASSERT( ((int)hdr->tpdu_li > 0) && ((int)hdr->tpdu_li < MLEN) ); + + m->m_next = data; + + ASSERT( hdr->tpdu_li < MLEN ); /* leave this in */ + ASSERT( hdr->tpdu_li != 0 ); /* leave this in */ + + m->m_len = hdr->tpdu_li ; + hdr->tpdu_li --; /* doesn't include the li field */ + + datalen = m_datalen( m ); /* total len */ + + ASSERT( datalen <= tpcb->tp_l_tpdusize ); /* may become a problem + when CLNP is used; leave in here for the time being */ + IFDEBUG(D_ACKSEND) + printf( + "4 after rADDOPTION csum_offset 0x%x, hdr->tpdu_li 0x%x\n", + csum_offset, hdr->tpdu_li); + ENDDEBUG + if( datalen > tpcb->tp_l_tpdusize ) { + printf("data len 0x%x tpcb->tp_l_tpdusize 0x%x\n", + datalen, tpcb->tp_l_tpdusize); + } + IFDEBUG(D_EMIT) + printf( + "tp_emit before gen_csum m_len 0x%x, csum_offset 0x%x, datalen 0x%x\n", + m->m_len, csum_offset, datalen); + ENDDEBUG + if( tpcb->tp_use_checksum || + (dutype == CR_TPDU_type && (tpcb->tp_class & TP_CLASS_4)) ) { + iso_gen_csum(m, csum_offset, datalen); + } + + IFDEBUG(D_EMIT) + printf("tp_emit before tpxxx_output tpcb 0x%x, dutype 0x%x, datalen 0x%x\n", + tpcb, dutype, datalen); + dump_buf(mtod(m, caddr_t), datalen); + ENDDEBUG + + IFPERF(tpcb) + if( dutype == DT_TPDU_type ) { + PStat(tpcb, Nb_to_ll) += (datalen - m->m_len); + tpmeas( tpcb->tp_lref, TPtime_to_ll, (struct timeval *)0, + seq, PStat(tpcb, Nb_to_ll), (datalen - m->m_len)); + } + ENDPERF + + IFTRACE(D_EMIT) + tptraceTPCB(TPPTtpduout, dutype, hdr, hdr->tpdu_li+1, datalen, 0); + ENDTRACE + IFDEBUG(D_EMIT) + printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", + tpcb, tpcb->tp_npcb, tpcb->tp_sock); + ENDDEBUG + + { extern char tp_delay; + + if( tp_delay ) + if( tpcb->tp_use_checksum == 0 ) { + register u_int i = tp_delay; + for (; i!= 0; i--) + (void) iso_check_csum(m, datalen); + } + } + ASSERT( m->m_len > 0 ); + error = (tpcb->tp_nlproto->nlp_output)(tpcb->tp_npcb, m, datalen, + !tpcb->tp_use_checksum); + IFDEBUG(D_EMIT) + printf("OUTPUT: returned 0x%x\n", error); + ENDDEBUG + IFTRACE(D_EMIT) + tptraceTPCB(TPPTmisc, + "tp_emit nlproto->output netservice returns datalen", + tpcb->tp_nlproto->nlp_output, tpcb->tp_netservice, error, datalen); + ENDTRACE +done: + if (error) { + if (dutype == AK_TPDU_type) + tp_ctimeout(tpcb, TM_sendack, 1); + if (error == E_CO_QFULL) { + tp_quench(tpcb, PRC_QUENCH); + return 0; + } + } + return error; +} +/* + * NAME: tp_error_emit() + * CALLED FROM: tp_input() when a DR or ER is to be issued in + * response to an input error. + * FUNCTION and ARGUMENTS: + * The error type is the first argument. + * The argument (sref) is the source reference on the bad incoming tpdu, + * and is used for a destination reference on the outgoing packet. + * (faddr) and (laddr) are the foreign and local addresses for this + * connection. + * (erdata) is a ptr to the errant incoming tpdu, and is copied into the + * outgoing ER, if an ER is to be issued. + * (erlen) is the number of octets of the errant tpdu that we should + * try to copy. + * (tpcb) is the pcb that describes the connection for which the bad tpdu + * arrived. + * RETURN VALUES: + * 0 OK + * ENOBUFS + * E* from net layer datagram output routine + * SIDE EFFECTS: + * + * NOTES: + */ + +int +tp_error_emit(error, sref, faddr, laddr, erdata, erlen, tpcb, cons_channel, + dgout_routine) + int error; + u_long sref; + struct sockaddr_iso *faddr, *laddr; + struct mbuf *erdata; + int erlen; + struct tp_pcb *tpcb; + caddr_t cons_channel; + int (*dgout_routine)(); +{ + int dutype; + int datalen = 0; + register struct tpdu *hdr; + register struct mbuf *m; + int csum_offset; + + IFTRACE(D_ERROR_EMIT) + tptrace(TPPTmisc, "tp_error_emit error sref tpcb erlen", + error, sref, tpcb, erlen); + ENDTRACE + IFDEBUG(D_ERROR_EMIT) + printf( + "tp_error_emit error 0x%x sref 0x%x tpcb 0x%x erlen 0x%x chan 0x%x\n", + error, sref, tpcb, erlen, cons_channel); + ENDDEBUG + + MGET(m, M_DONTWAIT, TPMT_TPHDR); + if (m == NULL) { + return ENOBUFS; + } + m->m_len = sizeof(struct tpdu); + m->m_act = MNULL; + + hdr = mtod(m, struct tpdu *); + + IFDEBUG(D_ERROR_EMIT) + printf("[error 0x%x] [error&0xff 0x%x] [(char)error 0x%x]\n", + error, error&0xff, (char)error); + ENDDEBUG + + + if (error & TP_ERROR_SNDC) + dutype = DC_TPDU_type; + else if (error & 0x40) { + error &= ~0x40; + dutype = ER_TPDU_type; + } else + dutype = DR_TPDU_type; + error &= 0xff; + + hdr->tpdu_type = dutype; + hdr->tpdu_cdt = 0; + + switch( dutype ) { + + case DC_TPDU_type: + IncStat(ts_DC_sent); + hdr->tpdu_li = 6; + hdr->tpdu_DCdref = htons(sref); + hdr->tpdu_DCsref = tpcb ? htons(tpcb->tp_lref) : 0; + IFDEBUG(D_ERROR_EMIT) + printf("DC case:\n"); + dump_buf( hdr, 6); + ENDDEBUG + /* forget the add'l information variable part */ + break; + + case DR_TPDU_type: + IncStat(ts_DR_sent); + hdr->tpdu_li = 7; + hdr->tpdu_DRdref = htons(sref); + hdr->tpdu_DRsref = 0; + hdr->tpdu_DRreason = (char)error; + IFDEBUG(D_ERROR_EMIT) + printf("DR case:\n"); + dump_buf( hdr, 7); + ENDDEBUG + /* forget the add'l information variable part */ + break; + + case ER_TPDU_type: + IncStat(ts_ER_sent); + hdr->tpdu_li = 5; + hdr->tpdu_ERreason = (char)error; + hdr->tpdu_ERdref = htons(sref); + break; + + default: + ASSERT(0); + printf("TP PANIC: bad dutype 0x%x\n", dutype); + } + + if(tpcb) + if( tpcb->tp_use_checksum ) { + ADDOPTION(TPP_checksum, hdr, 2, csum_offset /* dummy argument */); + csum_offset = hdr->tpdu_li - 2; + } + + ASSERT( hdr->tpdu_li < MLEN ); + + if (dutype == ER_TPDU_type) { + /* copy the errant tpdu into another 'variable part' */ + register caddr_t P; + + IFTRACE(D_ERROR_EMIT) + tptrace(TPPTmisc, "error_emit ER len tpduli", erlen, hdr->tpdu_li, + 0,0); + ENDTRACE + IFDEBUG(D_ERROR_EMIT) + printf("error_emit ER len 0x%x tpduli 0x%x\n", erlen, hdr->tpdu_li); + ENDDEBUG + + /* copy at most as many octets for which you have room */ + if (erlen + hdr->tpdu_li + 2 > TP_MAX_HEADER_LEN) + erlen = TP_MAX_HEADER_LEN - hdr->tpdu_li - 2; + + /* add the "invalid tpdu" parameter : required in class 0 */ + P = (caddr_t)hdr + (int)(hdr->tpdu_li); + vbptr(P)->tpv_code = TPP_invalid_tpdu; /* parameter code */ + vbptr(P)->tpv_len = erlen; /* parameter length */ + m->m_len = hdr->tpdu_li + 2; /* 1 for code, 1 for length */ + + /* tp_input very likely handed us an mbuf chain w/ nothing in + * the first mbuf and the data following the empty mbuf + */ + if(erdata->m_len == 0) { + erdata = m_free(erdata); /* returns the next mbuf on the chain */ + } + /* + * copy only up to the bad octet + * (or max that will fit in a header + */ + m->m_next = m_copy(erdata, 0, erlen); + hdr->tpdu_li += erlen + 2; + m_freem(erdata); + } else { + IFDEBUG(D_ERROR_EMIT) + printf("error_emit DR error tpduli 0x%x\n", error, hdr->tpdu_li); + dump_buf( (char *)hdr, hdr->tpdu_li ); + ENDDEBUG + m->m_len = hdr->tpdu_li ; + m_freem(erdata); + } + + hdr->tpdu_li --; + IFTRACE(D_ERROR_EMIT) + tptrace(TPPTtpduout, 2, hdr, hdr->tpdu_li+1, 0, 0); + ENDTRACE + + datalen = m_datalen( m); + if (tpcb) { + if( tpcb->tp_use_checksum ) { + IFTRACE(D_ERROR_EMIT) + tptrace(TPPTmisc, "before gen csum datalen", datalen,0,0,0); + ENDTRACE + IFDEBUG(D_ERROR_EMIT) + printf("before gen csum datalen 0x%x, csum_offset 0x%x\n", + datalen, csum_offset); + ENDDEBUG + + iso_gen_csum(m, csum_offset, datalen); + } + + IFDEBUG(D_ERROR_EMIT) + printf("OUTPUT: tpcb 0x%x, isop 0x%x, so 0x%x\n", + tpcb, tpcb->tp_npcb, tpcb->tp_sock); + ENDDEBUG + } + if (cons_channel) { +#ifdef TPCONS + struct pklcd *lcp = (struct pklcd *)cons_channel; + struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext; + + tpcons_dg_output(cons_channel, m, datalen); + /* was if (tpcb == 0) iso_pcbdetach(isop); */ + /* but other side may want to try again over same VC, + so, we'll depend on him closing it, but in case it gets forgotten + we'll mark it for garbage collection */ + lcp->lcd_flags |= X25_DG_CIRCUIT; + IFDEBUG(D_ERROR_EMIT) + printf("OUTPUT: dutype 0x%x channel 0x%x\n", + dutype, cons_channel); + ENDDEBUG +#else + printf("TP panic! cons channel 0x%x but not cons configured\n", + cons_channel); +#endif + } else if (tpcb) { + + IFDEBUG(D_ERROR_EMIT) + printf("tp_error_emit 1 sending DG: Laddr\n"); + dump_addr((struct sockaddr *)laddr); + printf("Faddr\n"); + dump_addr((struct sockaddr *)faddr); + ENDDEBUG + return (tpcb->tp_nlproto->nlp_dgoutput)( + &laddr->siso_addr, + &faddr->siso_addr, + m, datalen, + /* no route */ (caddr_t)0, !tpcb->tp_use_checksum); + } else if (dgout_routine) { + IFDEBUG(D_ERROR_EMIT) + printf("tp_error_emit sending DG: Laddr\n"); + dump_addr((struct sockaddr *)laddr); + printf("Faddr\n"); + dump_addr((struct sockaddr *)faddr); + ENDDEBUG + return (*dgout_routine)( &laddr->siso_addr, &faddr->siso_addr, + m, datalen, /* no route */ + (caddr_t)0, /* nochecksum==false */0); + } else { + IFDEBUG(D_ERROR_EMIT) + printf("tp_error_emit DROPPING \n", m); + ENDDEBUG + IncStat(ts_send_drop); + m_freem(m); + return 0; + } +} diff --git a/sys/netiso/tp_events.h b/sys/netiso/tp_events.h new file mode 100644 index 0000000..4822283 --- /dev/null +++ b/sys/netiso/tp_events.h @@ -0,0 +1,84 @@ +/* $Header$ */ +/* $Source$ */ +struct tp_event { + int ev_number; + struct timeval e_time; +#define TM_inact 0x0 +#define TM_retrans 0x1 +#define TM_sendack 0x2 +#define TM_notused 0x3 + + union{ +struct { SeqNum e_low; SeqNum e_high; int e_retrans; } EV_TM_reference; + +#define TM_reference 0x4 +struct { SeqNum e_low; SeqNum e_high; int e_retrans; } EV_TM_data_retrans; + +#define TM_data_retrans 0x5 +struct { + u_char e_reason; + } EV_ER_TPDU; + +#define ER_TPDU 0x6 +struct { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_int e_cdt; + } EV_CR_TPDU; + +#define CR_TPDU 0x7 +struct { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_short e_sref; + u_char e_reason; + } EV_DR_TPDU; + +#define DR_TPDU 0x8 +#define DC_TPDU 0x9 +struct { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_short e_sref; + u_int e_cdt; + } EV_CC_TPDU; + +#define CC_TPDU 0xa +struct { u_int e_cdt; + SeqNum e_seq; + SeqNum e_subseq; + u_char e_fcc_present; + } EV_AK_TPDU; + +#define AK_TPDU 0xb +struct { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + u_int e_eot; + SeqNum e_seq; + } EV_DT_TPDU; + +#define DT_TPDU 0xc +struct { struct mbuf *e_data; /* first field */ + int e_datalen; /* 2nd field */ + SeqNum e_seq; + } EV_XPD_TPDU; + +#define XPD_TPDU 0xd +struct { SeqNum e_seq; } EV_XAK_TPDU; + +#define XAK_TPDU 0xe +#define T_CONN_req 0xf +struct { u_char e_reason; } EV_T_DISC_req; + +#define T_DISC_req 0x10 +#define T_LISTEN_req 0x11 +#define T_DATA_req 0x12 +#define T_XPD_req 0x13 +#define T_USR_rcvd 0x14 +#define T_USR_Xrcvd 0x15 +#define T_DETACH 0x16 +#define T_NETRESET 0x17 +#define T_ACPT_req 0x18 + }ev_union; +};/* end struct event */ + +#define tp_NEVENTS 0x19 + +#define ATTR(X)ev_union.EV_/**/X/**/ diff --git a/sys/netiso/tp_inet.c b/sys/netiso/tp_inet.c new file mode 100644 index 0000000..fb01371 --- /dev/null +++ b/sys/netiso/tp_inet.c @@ -0,0 +1,688 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_inet.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * $Header: tp_inet.c,v 5.3 88/11/18 17:27:29 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_inet.c,v $ + * + * Here is where you find the inet-dependent code. We've tried + * keep all net-level and (primarily) address-family-dependent stuff + * out of the tp source, and everthing here is reached indirectly + * through a switch table (struct nl_protosw *) tpcb->tp_nlproto + * (see tp_pcb.c). + * The routines here are: + * in_getsufx: gets transport suffix out of an inpcb structure. + * in_putsufx: put transport suffix into an inpcb structure. + * in_putnetaddr: put a whole net addr into an inpcb. + * in_getnetaddr: get a whole net addr from an inpcb. + * in_cmpnetaddr: compare a whole net addr from an isopcb. + * in_recycle_suffix: clear suffix for reuse in inpcb + * tpip_mtu: figure out what size tpdu to use + * tpip_input: take a pkt from ip, strip off its ip header, give to tp + * tpip_output_dg: package a pkt for ip given 2 addresses & some data + * tpip_output: package a pkt for ip given an inpcb & some data + */ + +#ifdef INET + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <net/if.h> + +#include <netiso/tp_param.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_ip.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_tpdu.h> +#include <netinet/in_var.h> + +#ifndef ISO +#include <netiso/iso_chksum.c> +#endif + +/* + * NAME: in_getsufx() + + * CALLED FROM: pr_usrreq() on PRU_BIND, + * PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR + * + * FUNCTION, ARGUMENTS, and RETURN VALUE: + * Get a transport suffix from an inpcb structure (inp). + * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. + * + * RETURNS: internet port / transport suffix + * (CAST TO AN INT) + * + * SIDE EFFECTS: + * + * NOTES: + */ +in_getsufx(inp, lenp, data_out, which) + struct inpcb *inp; + u_short *lenp; + caddr_t data_out; + int which; +{ + *lenp = sizeof(u_short); + switch (which) { + case TP_LOCAL: + *(u_short *)data_out = inp->inp_lport; + return; + + case TP_FOREIGN: + *(u_short *)data_out = inp->inp_fport; + } + +} + +/* + * NAME: in_putsufx() + * + * CALLED FROM: tp_newsocket(); i.e., when a connection + * is being established by an incoming CR_TPDU. + * + * FUNCTION, ARGUMENTS: + * Put a transport suffix (found in name) into an inpcb structure (inp). + * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +/*ARGSUSED*/ +void +in_putsufx(inp, sufxloc, sufxlen, which) + struct inpcb *inp; + caddr_t sufxloc; + int which; +{ + if (which == TP_FOREIGN) { + bcopy(sufxloc, (caddr_t)&inp->inp_fport, sizeof(inp->inp_fport)); + } +} + +/* + * NAME: in_recycle_tsuffix() + * + * CALLED FROM: tp.trans whenever we go into REFWAIT state. + * + * FUNCTION and ARGUMENT: + * Called when a ref is frozen, to allow the suffix to be reused. + * (inp) is the net level pcb. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: This really shouldn't have to be done in a NET level pcb + * but... for the internet world that just the way it is done in BSD... + * The alternative is to have the port unusable until the reference + * timer goes off. + */ +void +in_recycle_tsuffix(inp) + struct inpcb *inp; +{ + inp->inp_fport = inp->inp_lport = 0; +} + +/* + * NAME: in_putnetaddr() + * + * CALLED FROM: + * tp_newsocket(); i.e., when a connection is being established by an + * incoming CR_TPDU. + * + * FUNCTION and ARGUMENTS: + * Copy a whole net addr from a struct sockaddr (name). + * into an inpcb (inp). + * The argument (which) takes values TP_LOCAL or TP_FOREIGN + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +in_putnetaddr(inp, name, which) + register struct inpcb *inp; + struct sockaddr_in *name; + int which; +{ + switch (which) { + case TP_LOCAL: + bcopy((caddr_t)&name->sin_addr, + (caddr_t)&inp->inp_laddr, sizeof(struct in_addr)); + /* won't work if the dst address (name) is INADDR_ANY */ + + break; + case TP_FOREIGN: + if( name != (struct sockaddr_in *)0 ) { + bcopy((caddr_t)&name->sin_addr, + (caddr_t)&inp->inp_faddr, sizeof(struct in_addr)); + } + } +} + +/* + * NAME: in_putnetaddr() + * + * CALLED FROM: + * tp_input() when a connection is being established by an + * incoming CR_TPDU, and considered for interception. + * + * FUNCTION and ARGUMENTS: + * Compare a whole net addr from a struct sockaddr (name), + * with that implicitly stored in an inpcb (inp). + * The argument (which) takes values TP_LOCAL or TP_FOREIGN + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +in_cmpnetaddr(inp, name, which) + register struct inpcb *inp; + register struct sockaddr_in *name; + int which; +{ + if (which == TP_LOCAL) { + if (name->sin_port && name->sin_port != inp->inp_lport) + return 0; + return (name->sin_addr.s_addr == inp->inp_laddr.s_addr); + } + if (name->sin_port && name->sin_port != inp->inp_fport) + return 0; + return (name->sin_addr.s_addr == inp->inp_faddr.s_addr); +} + +/* + * NAME: in_getnetaddr() + * + * CALLED FROM: + * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR + * FUNCTION and ARGUMENTS: + * Copy a whole net addr from an inpcb (inp) into + * an mbuf (name); + * The argument (which) takes values TP_LOCAL or TP_FOREIGN. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ + +void +in_getnetaddr( inp, name, which) + register struct mbuf *name; + struct inpcb *inp; + int which; +{ + register struct sockaddr_in *sin = mtod(name, struct sockaddr_in *); + bzero((caddr_t)sin, sizeof(*sin)); + switch (which) { + case TP_LOCAL: + sin->sin_addr = inp->inp_laddr; + sin->sin_port = inp->inp_lport; + break; + case TP_FOREIGN: + sin->sin_addr = inp->inp_faddr; + sin->sin_port = inp->inp_fport; + break; + default: + return; + } + name->m_len = sin->sin_len = sizeof (*sin); + sin->sin_family = AF_INET; +} + +/* + * NAME: tpip_mtu() + * + * CALLED FROM: + * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT + * + * FUNCTION, ARGUMENTS, and RETURN VALUE: + * + * Perform subnetwork dependent part of determining MTU information. + * It appears that setting a double pointer to the rtentry associated with + * the destination, and returning the header size for the network protocol + * suffices. + * + * SIDE EFFECTS: + * Sets tp_routep pointer in pcb. + * + * NOTES: + */ + +tpip_mtu(tpcb) +register struct tp_pcb *tpcb; +{ + struct inpcb *inp = (struct inpcb *)tpcb->tp_npcb; + + IFDEBUG(D_CONN) + printf("tpip_mtu(tpcb)\n", tpcb); + printf("tpip_mtu routing to addr 0x%x\n", inp->inp_faddr.s_addr); + ENDDEBUG + tpcb->tp_routep = &(inp->inp_route.ro_rt); + return (sizeof (struct ip)); + +} + +/* + * NAME: tpip_output() + * + * CALLED FROM: tp_emit() + * + * FUNCTION and ARGUMENTS: + * Take a packet(m0) from tp and package it so that ip will accept it. + * This means prepending space for the ip header and filling in a few + * of the fields. + * inp is the inpcb structure; datalen is the length of the data in the + * mbuf string m0. + * RETURNS: + * whatever (E*) is returned form the net layer output routine. + * + * SIDE EFFECTS: + * + * NOTES: + */ + +int +tpip_output(inp, m0, datalen, nochksum) + struct inpcb *inp; + struct mbuf *m0; + int datalen; + int nochksum; +{ + return tpip_output_dg( &inp->inp_laddr, &inp->inp_faddr, m0, datalen, + &inp->inp_route, nochksum); +} + +/* + * NAME: tpip_output_dg() + * + * CALLED FROM: tp_error_emit() + * + * FUNCTION and ARGUMENTS: + * This is a copy of tpip_output that takes the addresses + * instead of a pcb. It's used by the tp_error_emit, when we + * don't have an in_pcb with which to call the normal output rtn. + * + * RETURNS: ENOBUFS or whatever (E*) is + * returned form the net layer output routine. + * + * SIDE EFFECTS: + * + * NOTES: + */ + +/*ARGSUSED*/ +int +tpip_output_dg(laddr, faddr, m0, datalen, ro, nochksum) + struct in_addr *laddr, *faddr; + struct mbuf *m0; + int datalen; + struct route *ro; + int nochksum; +{ + register struct mbuf *m; + register struct ip *ip; + int error; + + IFDEBUG(D_EMIT) + printf("tpip_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); + ENDDEBUG + + + MGETHDR(m, M_DONTWAIT, TPMT_IPHDR); + if (m == 0) { + error = ENOBUFS; + goto bad; + } + m->m_next = m0; + MH_ALIGN(m, sizeof(struct ip)); + m->m_len = sizeof(struct ip); + + ip = mtod(m, struct ip *); + bzero((caddr_t)ip, sizeof *ip); + + ip->ip_p = IPPROTO_TP; + m->m_pkthdr.len = ip->ip_len = sizeof(struct ip) + datalen; + ip->ip_ttl = MAXTTL; + /* don't know why you need to set ttl; + * overlay doesn't even make this available + */ + + ip->ip_src = *laddr; + ip->ip_dst = *faddr; + + IncStat(ts_tpdu_sent); + IFDEBUG(D_EMIT) + dump_mbuf(m, "tpip_output_dg before ip_output\n"); + ENDDEBUG + + error = ip_output(m, (struct mbuf *)0, ro, IP_ALLOWBROADCAST, NULL); + + IFDEBUG(D_EMIT) + printf("tpip_output_dg after ip_output\n"); + ENDDEBUG + + return error; + +bad: + m_freem(m); + IncStat(ts_send_drop); + return error; +} + +/* + * NAME: tpip_input() + * + * CALLED FROM: + * ip's input routine, indirectly through the protosw. + * + * FUNCTION and ARGUMENTS: + * Take a packet (m) from ip, strip off the ip header and give it to tp + * + * RETURNS: No return value. + * + * SIDE EFFECTS: + * + * NOTES: + */ +ProtoHook +tpip_input(m, iplen) + struct mbuf *m; + int iplen; +{ + struct sockaddr_in src, dst; + register struct ip *ip; + int s = splnet(), hdrlen; + + IncStat(ts_pkt_rcvd); + + /* + * IP layer has already pulled up the IP header, + * but the first byte after the IP header may not be there, + * e.g. if you came in via loopback, so you have to do an + * m_pullup to before you can even look to see how much you + * really need. The good news is that m_pullup will round + * up to almost the next mbuf's worth. + */ + + + if((m = m_pullup(m, iplen + 1)) == MNULL) + goto discard; + CHANGE_MTYPE(m, TPMT_DATA); + + /* + * Now pull up the whole tp header: + * Unfortunately, there may be IP options to skip past so we + * just fetch it as an unsigned char. + */ + hdrlen = iplen + 1 + mtod(m, u_char *)[iplen]; + + if( m->m_len < hdrlen ) { + if((m = m_pullup(m, hdrlen)) == MNULL){ + IFDEBUG(D_TPINPUT) + printf("tp_input, pullup 2!\n"); + ENDDEBUG + goto discard; + } + } + /* + * cannot use tp_inputprep() here 'cause you don't + * have quite the same situation + */ + + IFDEBUG(D_TPINPUT) + dump_mbuf(m, "after tpip_input both pullups"); + ENDDEBUG + /* + * m_pullup may have returned a different mbuf + */ + ip = mtod(m, struct ip *); + + /* + * drop the ip header from the front of the mbuf + * this is necessary for the tp checksum + */ + m->m_len -= iplen; + m->m_data += iplen; + + src.sin_addr = *(struct in_addr *)&(ip->ip_src); + src.sin_family = AF_INET; + src.sin_len = sizeof(src); + dst.sin_addr = *(struct in_addr *)&(ip->ip_dst); + dst.sin_family = AF_INET; + dst.sin_len = sizeof(dst); + + (void) tp_input(m, (struct sockaddr *)&src, (struct sockaddr *)&dst, + 0, tpip_output_dg, 0); + return 0; + +discard: + IFDEBUG(D_TPINPUT) + printf("tpip_input DISCARD\n"); + ENDDEBUG + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "tpip_input DISCARD m", m,0,0,0); + ENDTRACE + m_freem(m); + IncStat(ts_recv_drop); + splx(s); + return 0; +} + + +#include <sys/protosw.h> +#include <netinet/ip_icmp.h> + +extern void tp_quench(); +/* + * NAME: tpin_quench() + * + * CALLED FROM: tpip_ctlinput() + * + * FUNCTION and ARGUMENTS: find the tpcb pointer and pass it to tp_quench + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ + +void +tpin_quench(inp) + struct inpcb *inp; +{ + tp_quench((struct tp_pcb *)inp->inp_socket->so_pcb, PRC_QUENCH); +} + +/* + * NAME: tpip_ctlinput() + * + * CALLED FROM: + * The network layer through the protosw table. + * + * FUNCTION and ARGUMENTS: + * When clnp gets an ICMP msg this gets called. + * It either returns an error status to the user or + * causes all connections on this address to be aborted + * by calling the appropriate xx_notify() routine. + * (cmd) is the type of ICMP error. + * (sa) the address of the sender + * + * RETURNS: Nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ +ProtoHook +tpip_ctlinput(cmd, sin) + int cmd; + struct sockaddr_in *sin; +{ + extern u_char inetctlerrmap[]; + extern struct in_addr zeroin_addr; + void tp_quench __P((struct inpcb *,int)); + void tpin_abort __P((struct inpcb *,int)); + + if (sin->sin_family != AF_INET && sin->sin_family != AF_IMPLINK) + return 0; + if (sin->sin_addr.s_addr == INADDR_ANY) + return 0; + if (cmd < 0 || cmd > PRC_NCMDS) + return 0; + switch (cmd) { + + case PRC_QUENCH: + in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, + zeroin_addr, 0, cmd, tp_quench); + break; + + case PRC_ROUTEDEAD: + case PRC_HOSTUNREACH: + case PRC_UNREACH_NET: + case PRC_IFDOWN: + case PRC_HOSTDEAD: + in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, + zeroin_addr, 0, cmd, in_rtchange); + break; + + default: + /* + case PRC_MSGSIZE: + case PRC_UNREACH_HOST: + case PRC_UNREACH_PROTOCOL: + case PRC_UNREACH_PORT: + case PRC_UNREACH_NEEDFRAG: + case PRC_UNREACH_SRCFAIL: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + case PRC_TIMXCEED_INTRANS: + case PRC_TIMXCEED_REASS: + case PRC_PARAMPROB: + */ + in_pcbnotify(&tp_inpcb, (struct sockaddr *)sin, 0, + zeroin_addr, 0, cmd, tpin_abort); + } + return 0; +} + +/* + * NAME: tpin_abort() + * + * CALLED FROM: + * xxx_notify() from tp_ctlinput() when + * net level gets some ICMP-equiv. type event. + * + * FUNCTION and ARGUMENTS: + * Cause the connection to be aborted with some sort of error + * reason indicating that the network layer caused the abort. + * Fakes an ER TPDU so we can go through the driver. + * + * RETURNS: Nothing + * + * SIDE EFFECTS: + * + * NOTES: + */ + +ProtoHook +tpin_abort(inp) + struct inpcb *inp; +{ + struct tp_event e; + + e.ev_number = ER_TPDU; + e.ATTR(ER_TPDU).e_reason = ENETRESET; + (void) tp_driver((struct tp_pcb *)inp->inp_ppcb, &e); + return 0; +} + +#ifdef ARGO_DEBUG +dump_inaddr(addr) + register struct sockaddr_in *addr; +{ + printf("INET: port 0x%x; addr 0x%x\n", addr->sin_port, addr->sin_addr); +} +#endif /* ARGO_DEBUG */ +#endif /* INET */ diff --git a/sys/netiso/tp_input.c b/sys/netiso/tp_input.c new file mode 100644 index 0000000..a071a5d --- /dev/null +++ b/sys/netiso/tp_input.c @@ -0,0 +1,1624 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_input.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_input.c,v 5.6 88/11/18 17:27:38 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_input.c,v $ + * + * tp_input() gets an mbuf chain from ip. Actually, not directly + * from ip, because ip calls a net-level routine that strips off + * the net header and then calls tp_input(), passing the proper type + * of addresses for the address family in use (how it figures out + * which AF is not yet determined.) + * + * Decomposing the tpdu is some of the most laughable code. The variable-length + * parameters and the problem of non-aligned memory references + * necessitates such abominations as the macros WHILE_OPTIONS (q.v. below) + * to loop through the header and decompose it. + * + * The routine tp_newsocket() is called when a CR comes in for a listening + * socket. tp_input calls sonewconn() and tp_newsocket() to set up the + * "child" socket. Most tpcb values are copied from the parent tpcb into + * the child. + * + * Also in here is tp_headersize() (grot) which tells the expected size + * of a tp header, to be used by other layers. It's in here because it + * uses the static structure tpdu_info. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <netiso/iso.h> +#include <netiso/iso_errno.h> +#include <netiso/iso_pcb.h> +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_tpdu.h> + +#include <net/if.h> +#ifdef TRUE +#undef FALSE +#undef TRUE +#endif +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> + +int iso_check_csum(), tp_driver(), tp_headersize(), tp_error_emit(); + +/* + #ifdef lint + #undef ATTR + #define ATTR(X)ev_number + #endif lint +*/ + +struct mbuf * +tp_inputprep(m) + register struct mbuf *m; +{ + int hdrlen; + + IFDEBUG(D_TPINPUT) + printf("tp_inputprep: m 0x%x\n", m) ; + ENDDEBUG + + while( m->m_len < 1 ) { + /* The "m_free" logic + * if( (m = m_free(m)) == MNULL ) + * return (struct mbuf *)0; + * would cause a system crash if ever executed. + * This logic will be executed if the first mbuf + * in the chain only contains a CLNP header. The m_free routine + * will release the mbuf containing the CLNP header from the + * chain and the new head of the chain will not have the + * M_PKTHDR bit set. This routine, tp_inputprep, will + * eventually call the "sbappendaddr" routine. "sbappendaddr" + * calls "panic" if M_PKTHDR is not set. m_pullup is a cheap + * way of keeping the head of the chain from being freed. + */ + if((m = m_pullup(m, 1)) == MNULL) + return (MNULL); + } + if(((int)m->m_data) & 0x3) { + /* If we are not 4-byte aligned, we have to be + * above the beginning of the mbuf, and it is ok just + * to slide it back. + */ + caddr_t ocp = m->m_data; + + m->m_data = (caddr_t)(((int)m->m_data) & ~0x3); + bcopy(ocp, m->m_data, (unsigned)m->m_len); + } + CHANGE_MTYPE(m, TPMT_DATA); + + /* we KNOW that there is at least 1 byte in this mbuf + and that it is hdr->tpdu_li XXXXXXX! */ + + hdrlen = 1 + *mtod( m, u_char *); + + /* + * now pull up the whole tp header + */ + if ( m->m_len < hdrlen) { + if ((m = m_pullup(m, hdrlen)) == MNULL ) { + IncStat(ts_recv_drop); + return (struct mbuf *)0; + } + } + IFDEBUG(D_INPUT) + printf( + " at end: m 0x%x hdr->tpdu_li 0x%x m_len 0x%x\n",m, + hdrlen, m->m_len); + ENDDEBUG + return m; +} + +/* begin groan + * -- this array and the following macros allow you to step through the + * parameters of the variable part of a header + * note that if for any reason the values of the **_TPDU macros (in tp_events.h) + * should change, this array has to be rearranged + */ + +#define TP_LEN_CLASS_0_INDEX 2 +#define TP_MAX_DATA_INDEX 3 + +static u_char tpdu_info[][4] = +{ +/* length max data len */ +/* reg fmt xtd fmt class 0 */ + /* UNUSED 0x0 */ 0x0 , 0x0, 0x0, 0x0, + /* XPD_TPDU_type 0x1 */ 0x5, 0x8, 0x0, TP_MAX_XPD_DATA, + /* XAK_TPDU_type 0x2 */ 0x5 , 0x8, 0x0, 0x0, + /* GR_TPDU_type 0x3 */ 0x0 , 0x0, 0x0, 0x0, + /* UNUSED 0x4 */ 0x0 , 0x0, 0x0, 0x0, + /* UNUSED 0x5 */ 0x0 , 0x0, 0x0, 0x0, + /* AK_TPDU_type 0x6 */ 0x5, 0xa, 0x0, 0x0, + /* ER_TPDU_type 0x7 */ 0x5, 0x5, 0x0, 0x0, + /* DR_TPDU_type 0x8 */ 0x7, 0x7, 0x7, TP_MAX_DR_DATA, + /* UNUSED 0x9 */ 0x0 , 0x0, 0x0, 0x0, + /* UNUSED 0xa */ 0x0 , 0x0, 0x0, 0x0, + /* UNUSED 0xb */ 0x0 , 0x0, 0x0, 0x0, + /* DC_TPDU_type 0xc */ 0x6, 0x6, 0x0, 0x0, + /* CC_TPDU_type 0xd */ 0x7, 0x7, 0x7, TP_MAX_CC_DATA, + /* CR_TPDU_type 0xe */ 0x7, 0x7, 0x7, TP_MAX_CR_DATA, + /* DT_TPDU_type 0xf */ 0x5, 0x8, 0x3, 0x0, +}; + +#define CHECK(Phrase, Erval, Stat, Whattodo, Loc)\ + if (Phrase) {error = (Erval); errlen = (int)(Loc); IncStat(Stat);\ + goto Whattodo; } + +/* + * WHENEVER YOU USE THE FOLLOWING MACRO, + * BE SURE THE TPDUTYPE IS A LEGIT VALUE FIRST! + */ + +#define WHILE_OPTIONS(P, hdr, format)\ +{ register caddr_t P = tpdu_info[(hdr)->tpdu_type][(format)] + (caddr_t)hdr;\ + caddr_t PLIM = 1 + hdr->tpdu_li + (caddr_t)hdr;\ + for (;; P += 2 + ((struct tp_vbp *)P)->tpv_len) {\ + CHECK((P > PLIM), E_TP_LENGTH_INVAL, ts_inv_length,\ + respond, P - (caddr_t)hdr);\ + if (P == PLIM) break; + +#define END_WHILE_OPTIONS(P) } } + +/* end groan */ + +/* + * NAME: tp_newsocket() + * + * CALLED FROM: + * tp_input() on incoming CR, when a socket w/ the called suffix + * is awaiting a connection request + * + * FUNCTION and ARGUMENTS: + * Create a new socket structure, attach to it a new transport pcb, + * using a copy of the net level pcb for the parent socket. + * (so) is the parent socket. + * (fname) is the foreign address (all that's used is the nsap portion) + * + * RETURN VALUE: + * a new socket structure, being this end of the newly formed connection. + * + * SIDE EFFECTS: + * Sets a few things in the tpcb and net level pcb + * + * NOTES: + */ +static struct socket * +tp_newsocket(so, fname, cons_channel, class_to_use, netservice) + struct socket *so; + struct sockaddr *fname; + caddr_t cons_channel; + u_char class_to_use; + u_int netservice; +{ + register struct tp_pcb *tpcb = sototpcb(so); /* old tpcb, needed below */ + register struct tp_pcb *newtpcb; + + /* + * sonewconn() gets a new socket structure, + * a new lower layer pcb and a new tpcb, + * but the pcbs are unnamed (not bound) + */ + IFTRACE(D_NEWSOCK) + tptraceTPCB(TPPTmisc, "newsock: listg_so, _tpcb, so_head", + so, tpcb, so->so_head, 0); + ENDTRACE + + if ((so = sonewconn(so, SS_ISCONFIRMING)) == (struct socket *)0) + return so; + IFTRACE(D_NEWSOCK) + tptraceTPCB(TPPTmisc, "newsock: after newconn so, so_head", + so, so->so_head, 0, 0); + ENDTRACE + + IFDEBUG(D_NEWSOCK) + printf("tp_newsocket(channel 0x%x) after sonewconn so 0x%x \n", + cons_channel, so); + dump_addr(fname); + { + struct socket *t, *head ; + + head = so->so_head; + t = so; + printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", + t, t->so_head, t->so_q0, t->so_q0len); + while( (t=t->so_q0) && t!= so && t!= head) + printf("so 0x%x so_head 0x%x so_q0 0x%x, q0len %d\n", + t, t->so_head, t->so_q0, t->so_q0len); + } + ENDDEBUG + + /* + * before we clobber the old tpcb ptr, get these items from the parent pcb + */ + newtpcb = sototpcb(so); + newtpcb->_tp_param = tpcb->_tp_param; + newtpcb->tp_flags = tpcb->tp_flags; + newtpcb->tp_lcredit = tpcb->tp_lcredit; + newtpcb->tp_l_tpdusize = tpcb->tp_l_tpdusize; + newtpcb->tp_lsuffixlen = tpcb->tp_lsuffixlen; + bcopy( tpcb->tp_lsuffix, newtpcb->tp_lsuffix, newtpcb->tp_lsuffixlen); + + if( /* old */ tpcb->tp_ucddata) { + /* + * These data are the connect- , confirm- or disconnect- data. + */ + struct mbuf *conndata; + + conndata = m_copy(tpcb->tp_ucddata, 0, (int)M_COPYALL); + IFDEBUG(D_CONN) + dump_mbuf(conndata, "conndata after mcopy"); + ENDDEBUG + newtpcb->tp_ucddata = conndata; + } + + tpcb = newtpcb; + tpcb->tp_state = TP_LISTENING; + tpcb->tp_class = class_to_use; + tpcb->tp_netservice = netservice; + + + ASSERT( fname != 0 ) ; /* just checking */ + if ( fname ) { + /* + * tp_route_to takes its address argument in the form of an mbuf. + */ + struct mbuf *m; + int err; + + MGET(m, M_DONTWAIT, MT_SONAME); /* mbuf type used is confusing */ + if (m) { + /* + * this seems a bit grotesque, but tp_route_to expects + * an mbuf * instead of simply a sockaddr; it calls the ll + * pcb_connect, which expects the name/addr in an mbuf as well. + * sigh. + */ + bcopy((caddr_t)fname, mtod(m, caddr_t), fname->sa_len); + m->m_len = fname->sa_len; + + /* grot : have to say the kernel can override params in + * the passive open case + */ + tpcb->tp_dont_change_params = 0; + err = tp_route_to( m, tpcb, cons_channel); + m_free(m); + + if (!err) + goto ok; + } + IFDEBUG(D_CONN) + printf("tp_route_to FAILED! detaching tpcb 0x%x, so 0x%x\n", + tpcb, so); + ENDDEBUG + (void) tp_detach(tpcb); + return 0; + } +ok: + IFDEBUG(D_TPINPUT) + printf("tp_newsocket returning so 0x%x, sototpcb(so) 0x%x\n", + so, sototpcb(so)); + ENDDEBUG + return so; +} + +#ifndef TPCONS +tpcons_output() +{ + return(0); +} +#endif /* !CONS */ + +/* + * NAME: tp_input() + * + * CALLED FROM: + * net layer input routine + * + * FUNCTION and ARGUMENTS: + * Process an incoming TPDU (m), finding the associated tpcb if there + * is one. Create the appropriate type of event and call the driver. + * (faddr) and (laddr) are the foreign and local addresses. + * + * When tp_input() is called we KNOW that the ENTIRE TP HEADER + * has been m_pullup-ed. + * + * RETURN VALUE: Nada + * + * SIDE EFFECTS: + * When using COSNS it may affect the state of the net-level pcb + * + * NOTE: + * The initial value of acktime is 2 so that we will never + * have a 0 value for tp_peer_acktime. It gets used in the + * computation of the retransmission timer value, and so it + * mustn't be zero. + * 2 seems like a reasonable minimum. + */ +ProtoHook +tp_input(m, faddr, laddr, cons_channel, dgout_routine, ce_bit) + register struct mbuf *m; + struct sockaddr *faddr, *laddr; /* NSAP addresses */ + caddr_t cons_channel; + int (*dgout_routine)(); + int ce_bit; + +{ + register struct tp_pcb *tpcb; + register struct tpdu *hdr; + struct socket *so; + struct tp_event e; + int error; + unsigned dutype; + u_short dref, sref, acktime, subseq; + u_char preferred_class, class_to_use, pdusize; + u_char opt, dusize, addlopt, version; +#ifdef TP_PERF_MEAS + u_char perf_meas; +#endif /* TP_PERF_MEAS */ + u_char fsufxlen, lsufxlen; + caddr_t fsufxloc, lsufxloc; + int tpdu_len; + u_int takes_data; + u_int fcc_present; + int errlen; + struct tp_conn_param tpp; + int tpcons_output(); + +again: + hdr = mtod(m, struct tpdu *); + tpcb = 0; + error = errlen = tpdu_len = 0; + takes_data = fcc_present = FALSE; + acktime = 2; sref = subseq = 0; + fsufxloc = lsufxloc = NULL; + fsufxlen = lsufxlen = + preferred_class = class_to_use = pdusize = addlopt = 0; + dusize = TP_DFL_TPDUSIZE; +#ifdef TP_PERF_MEAS + GET_CUR_TIME( &e.e_time ); perf_meas = 0; +#endif /* TP_PERF_MEAS */ + + IFDEBUG(D_TPINPUT) + printf("tp_input(0x%x, ... 0x%x)\n", m, cons_channel); + ENDDEBUG + + + /* + * get the actual tpdu length - necessary for monitoring + * and for checksumming + * + * Also, maybe measure the mbuf chain lengths and sizes. + */ + + { register struct mbuf *n=m; +# ifdef ARGO_DEBUG + int chain_length = 0; +# endif ARGO_DEBUG + + for(;;) { + tpdu_len += n->m_len; + IFDEBUG(D_MBUF_MEAS) + if( n->m_flags & M_EXT) { + IncStat(ts_mb_cluster); + } else { + IncStat(ts_mb_small); + } + chain_length ++; + ENDDEBUG + if (n->m_next == MNULL ) { + break; + } + n = n->m_next; + } + IFDEBUG(D_MBUF_MEAS) + if(chain_length > 16) + chain_length = 0; /* zero used for anything > 16 */ + tp_stat.ts_mb_len_distr[chain_length] ++; + ENDDEBUG + } + IFTRACE(D_TPINPUT) + tptraceTPCB(TPPTtpduin, hdr->tpdu_type, hdr, hdr->tpdu_li+1, tpdu_len, + 0); + ENDTRACE + + dref = ntohs((short)hdr->tpdu_dref); + sref = ntohs((short)hdr->tpdu_sref); + dutype = (int)hdr->tpdu_type; + + IFDEBUG(D_TPINPUT) + printf("input: dutype 0x%x cons_channel 0x%x dref 0x%x\n", dutype, + cons_channel, dref); + printf("input: dref 0x%x sref 0x%x\n", dref, sref); + ENDDEBUG + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "channel dutype dref ", + cons_channel, dutype, dref, 0); + ENDTRACE + + +#ifdef ARGO_DEBUG + if( (dutype < TP_MIN_TPDUTYPE) || (dutype > TP_MAX_TPDUTYPE)) { + printf("BAD dutype! 0x%x, channel 0x%x dref 0x%x\n", + dutype, cons_channel, dref); + dump_buf (m, sizeof( struct mbuf )); + + IncStat(ts_inv_dutype); + goto discard; + } +#endif /* ARGO_DEBUG */ + + CHECK( (dutype < TP_MIN_TPDUTYPE || dutype > TP_MAX_TPDUTYPE), + E_TP_INV_TPDU, ts_inv_dutype, respond, + 2 ); + /* unfortunately we can't take the address of the tpdu_type field, + * since it's a bit field - so we just use the constant offset 2 + */ + + /* Now this isn't very neat but since you locate a pcb one way + * at the beginning of connection establishment, and by + * the dref for each tpdu after that, we have to treat CRs differently + */ + if ( dutype == CR_TPDU_type ) { + u_char alt_classes = 0; + + preferred_class = 1 << hdr->tpdu_CRclass; + opt = hdr->tpdu_CRoptions; + + WHILE_OPTIONS(P, hdr, 1 ) /* { */ + + switch( vbptr(P)->tpv_code ) { + + case TPP_tpdu_size: + vb_getval(P, u_char, dusize); + IFDEBUG(D_TPINPUT) + printf("CR dusize 0x%x\n", dusize); + ENDDEBUG + /* COS tests: NBS IA (Dec. 1987) Sec. 4.5.2.1 */ + if (dusize < TP_MIN_TPDUSIZE || dusize > TP_MAX_TPDUSIZE) + dusize = TP_DFL_TPDUSIZE; + break; + case TPP_ptpdu_size: + switch (vbptr(P)->tpv_len) { + case 1: pdusize = vbval(P, u_char); break; + case 2: pdusize = ntohs(vbval(P, u_short)); break; + default: ; + IFDEBUG(D_TPINPUT) + printf("malformed prefered TPDU option\n"); + ENDDEBUG + } + break; + case TPP_addl_opt: + vb_getval(P, u_char, addlopt); + break; + case TPP_calling_sufx: + /* could use vb_getval, but we want to save the loc & len + * for later use + */ + fsufxloc = (caddr_t) &vbptr(P)->tpv_val; + fsufxlen = vbptr(P)->tpv_len; + IFDEBUG(D_TPINPUT) + printf("CR fsufx:"); + { register int j; + for(j=0; j<fsufxlen; j++ ) { + printf(" 0x%x. ", *((caddr_t)(fsufxloc+j)) ); + } + printf("\n"); + } + ENDDEBUG + break; + case TPP_called_sufx: + /* could use vb_getval, but we want to save the loc & len + * for later use + */ + lsufxloc = (caddr_t) &vbptr(P)->tpv_val; + lsufxlen = vbptr(P)->tpv_len; + IFDEBUG(D_TPINPUT) + printf("CR lsufx:"); + { register int j; + for(j=0; j<lsufxlen; j++ ) { + printf(" 0x%x. ", *((u_char *)(lsufxloc+j)) ); + } + printf("\n"); + } + ENDDEBUG + break; + +#ifdef TP_PERF_MEAS + case TPP_perf_meas: + vb_getval(P, u_char, perf_meas); + break; +#endif /* TP_PERF_MEAS */ + + case TPP_vers: + /* not in class 0; 1 octet; in CR_TPDU only */ + /* COS tests says if version wrong, use default version!?XXX */ + CHECK( (vbval(P, u_char) != TP_VERSION ), + E_TP_INV_PVAL, ts_inv_pval, setversion, + (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ); + setversion: + version = vbval(P, u_char); + break; + case TPP_acktime: + vb_getval(P, u_short, acktime); + acktime = ntohs(acktime); + acktime = acktime/500; /* convert to slowtimo ticks */ + if((short)acktime <=0 ) + acktime = 2; /* don't allow a bad peer to screw us up */ + IFDEBUG(D_TPINPUT) + printf("CR acktime 0x%x\n", acktime); + ENDDEBUG + break; + + case TPP_alt_class: + { + u_char *aclass = 0; + register int i; + static u_char bad_alt_classes[5] = + { ~0, ~3, ~5, ~0xf, ~0x1f}; + + aclass = + (u_char *) &(((struct tp_vbp *)P)->tpv_val); + for (i = ((struct tp_vbp *)P)->tpv_len; i>0; i--) { + alt_classes |= (1<<((*aclass++)>>4)); + } + CHECK( (bad_alt_classes[hdr->tpdu_CRclass] & alt_classes), + E_TP_INV_PVAL, ts_inv_aclass, respond, + ((caddr_t)aclass) - (caddr_t)hdr); + IFDEBUG(D_TPINPUT) + printf("alt_classes 0x%x\n", alt_classes); + ENDDEBUG + } + break; + + case TPP_security: + case TPP_residER: + case TPP_priority: + case TPP_transdelay: + case TPP_throughput: + case TPP_addl_info: + case TPP_subseq: + default: + IFDEBUG(D_TPINPUT) + printf("param ignored CR_TPDU code= 0x%x\n", + vbptr(P)->tpv_code); + ENDDEBUG + IncStat(ts_param_ignored); + break; + + case TPP_checksum: + IFDEBUG(D_TPINPUT) + printf("CR before cksum\n"); + ENDDEBUG + + CHECK( iso_check_csum(m, tpdu_len), + E_TP_INV_PVAL, ts_bad_csum, discard, 0) + + IFDEBUG(D_TPINPUT) + printf("CR before cksum\n"); + ENDDEBUG + break; + } + + /* } */ END_WHILE_OPTIONS(P) + + if (lsufxlen == 0) { + /* can't look for a tpcb w/o any called sufx */ + error = E_TP_LENGTH_INVAL; + IncStat(ts_inv_sufx); + goto respond; + } else { + register struct tp_pcb *t; + /* + * The intention here is to trap all CR requests + * to a given nsap, for constructing transport + * service bridges at user level; so these + * intercepts should precede the normal listens. + * Phrasing the logic in this way also allows for + * mop-up listeners, which we don't currently implement. + * We also wish to have a single socket be able to + * listen over any network service provider, + * (cons or clns or ip). + */ + for (t = tp_listeners; t ; t = t->tp_nextlisten) + if ((t->tp_lsuffixlen == 0 || + (lsufxlen == t->tp_lsuffixlen && + bcmp(lsufxloc, t->tp_lsuffix, lsufxlen) == 0)) && + ((t->tp_flags & TPF_GENERAL_ADDR) || + (laddr->sa_family == t->tp_domain && + (*t->tp_nlproto->nlp_cmpnetaddr) + (t->tp_npcb, laddr, TP_LOCAL)))) + break; + + CHECK(t == 0, E_TP_NO_SESSION, ts_inv_sufx, respond, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + /* _tpduf is the fixed part; add 2 to get the dref bits of + * the fixed part (can't take the address of a bit field) + */ + IFDEBUG(D_TPINPUT) + printf("checking if dup CR\n"); + ENDDEBUG + tpcb = t; + for (t = tpcb->tp_next; t != tpcb; t = t->tp_next) { + if (sref != t->tp_fref) + continue; + if ((*tpcb->tp_nlproto->nlp_cmpnetaddr)( + t->tp_npcb, faddr, TP_FOREIGN)) { + IFDEBUG(D_TPINPUT) + printf("duplicate CR discarded\n"); + ENDDEBUG + goto discard; + } + } + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "tp_input: tpcb *lsufxloc tpstate", + tpcb, *lsufxloc, tpcb->tp_state, 0); + ENDTRACE + } + + /* + * WE HAVE A TPCB + * already know that the classes in the CR match at least + * one class implemented, but we don't know yet if they + * include any classes permitted by this server. + */ + + IFDEBUG(D_TPINPUT) + printf("HAVE A TPCB 1: 0x%x\n", tpcb); + ENDDEBUG + IFDEBUG(D_CONN) + printf( +"CR: bef CHKS: flags 0x%x class_to_use 0x%x alt 0x%x opt 0x%x tp_class 0x%x\n", + tpcb->tp_flags, class_to_use, alt_classes, opt, tpcb->tp_class); + ENDDEBUG + /* tpcb->tp_class doesn't include any classes not implemented */ + class_to_use = (preferred_class & tpcb->tp_class); + if( (class_to_use = preferred_class & tpcb->tp_class) == 0 ) + class_to_use = alt_classes & tpcb->tp_class; + + class_to_use = 1 << tp_mask_to_num(class_to_use); + + { + tpp = tpcb->_tp_param; + tpp.p_class = class_to_use; + tpp.p_tpdusize = dusize; + tpp.p_ptpdusize = pdusize; + tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; + tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; + tpp.p_use_checksum = (tpp.p_class == TP_CLASS_0)?0: + (addlopt & TPAO_NO_CSUM) == 0; + tpp.p_version = version; +#ifdef notdef + tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; + tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; + tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; +#endif /* notdef */ + + CHECK( + tp_consistency(tpcb, 0 /* not force or strict */, &tpp) != 0, + E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, + (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) + /* ^ more or less the location of class */ + ) + } + IFTRACE(D_CONN) + tptrace(TPPTmisc, + "after 1 consist class_to_use class, out, tpconsout", + class_to_use, + tpcb->tp_class, dgout_routine, tpcons_output + ); + ENDTRACE + CHECK( + ((class_to_use == TP_CLASS_0)&&(dgout_routine != tpcons_output)), + E_TP_NEGOT_FAILED, ts_negotfailed, clear_parent_tcb, + (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) + /* ^ more or less the location of class */ + ) + IFDEBUG(D_CONN) + printf("CR: after CRCCCHECKS: tpcb 0x%x, flags 0x%x\n", + tpcb, tpcb->tp_flags); + ENDDEBUG + takes_data = TRUE; + e.ATTR(CR_TPDU).e_cdt = hdr->tpdu_CRcdt; + e.ev_number = CR_TPDU; + + so = tpcb->tp_sock; + if (so->so_options & SO_ACCEPTCONN) { + struct tp_pcb *parent_tpcb = tpcb; + /* + * Create a socket, tpcb, ll pcb, etc. + * for this newborn connection, and fill in all the values. + */ + IFDEBUG(D_CONN) + printf("abt to call tp_newsocket(0x%x, 0x%x, 0x%x, 0x%x)\n", + so, laddr, faddr, cons_channel); + ENDDEBUG + if( (so = + tp_newsocket(so, faddr, cons_channel, + class_to_use, + ((tpcb->tp_netservice == IN_CLNS) ? IN_CLNS : + (dgout_routine == tpcons_output)?ISO_CONS:ISO_CLNS)) + ) == (struct socket *)0 ) { + /* note - even if netservice is IN_CLNS, as far as + * the tp entity is concerned, the only differences + * are CO vs CL + */ + IFDEBUG(D_CONN) + printf("tp_newsocket returns 0\n"); + ENDDEBUG + goto discard; + clear_parent_tcb: + tpcb = 0; + goto respond; + } + tpcb = sototpcb(so); + insque(tpcb, parent_tpcb); + + /* + * Stash the addresses in the net level pcb + * kind of like a pcbconnect() but don't need + * or want all those checks. + */ + (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, faddr, TP_FOREIGN); + (tpcb->tp_nlproto->nlp_putnetaddr)(tpcb->tp_npcb, laddr, TP_LOCAL); + + /* stash the f suffix in the new tpcb */ + if (tpcb->tp_fsuffixlen = fsufxlen) { + bcopy(fsufxloc, tpcb->tp_fsuffix, fsufxlen); + (tpcb->tp_nlproto->nlp_putsufx) + (tpcb->tp_npcb, fsufxloc, fsufxlen, TP_FOREIGN); + } + /* stash the l suffix in the new tpcb */ + tpcb->tp_lsuffixlen = lsufxlen; + bcopy(lsufxloc, tpcb->tp_lsuffix, lsufxlen); + (tpcb->tp_nlproto->nlp_putsufx) + (tpcb->tp_npcb, lsufxloc, lsufxlen, TP_LOCAL); +#ifdef TP_PERF_MEAS + if( tpcb->tp_perf_on = perf_meas ) { /* assignment */ + /* ok, let's create an mbuf for stashing the + * statistics if one doesn't already exist + */ + (void) tp_setup_perf(tpcb); + } +#endif /* TP_PERF_MEAS */ + tpcb->tp_fref = sref; + + /* We've already checked for consistency with the options + * set in tpp, but we couldn't set them earlier because + * we didn't want to change options in the LISTENING tpcb. + * Now we set the options in the new socket's tpcb. + */ + (void) tp_consistency( tpcb, TP_FORCE, &tpp); + + if(!tpcb->tp_use_checksum) + IncStat(ts_csum_off); + if(tpcb->tp_xpd_service) + IncStat(ts_use_txpd); + if(tpcb->tp_xtd_format) + IncStat(ts_xtd_fmt); + + tpcb->tp_peer_acktime = acktime; + + /* + * The following kludge is used to test retransmissions and + * timeout during connection establishment. + */ + IFDEBUG(D_ZDREF) + IncStat(ts_zdebug); + /*tpcb->tp_fref = 0;*/ + ENDDEBUG + } + LOCAL_CREDIT(tpcb); + IncStat(ts_CR_rcvd); + if (!tpcb->tp_cebit_off) { + tpcb->tp_win_recv = tp_start_win << 8; + tpcb->tp_cong_sample.cs_size = 0; + CONG_INIT_SAMPLE(tpcb); + CONG_UPDATE_SAMPLE(tpcb, ce_bit); + } + } else if ( dutype == ER_TPDU_type ) { + /* + * ER TPDUs have to be recognized separately + * because they don't necessarily have a tpcb + * with them and we don't want err out looking for such + * a beast. + * We could put a bunch of little kludges in the + * next section of code so it would avoid references to tpcb + * if dutype == ER_TPDU_type but we don't want code for ERs to + * mess up code for data transfer. + */ + IncStat(ts_ER_rcvd); + e.ev_number = ER_TPDU; + e.ATTR(ER_TPDU).e_reason = (u_char)hdr->tpdu_ERreason; + CHECK (((int)dref <= 0 || dref >= tp_refinfo.tpr_size || + (tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 || + tpcb->tp_refstate == REF_FREE || + tpcb->tp_refstate == REF_FROZEN), + E_TP_MISM_REFS, ts_inv_dref, discard, 0) + + } else { + /* tpdu type is CC, XPD, XAK, GR, AK, DR, DC, or DT */ + + /* In the next 4 checks, + * _tpduf is the fixed part; add 2 to get the dref bits of + * the fixed part (can't take the address of a bit field) + */ +#ifdef TPCONS + if (cons_channel && dutype == DT_TPDU_type) { + struct isopcb *isop = ((struct isopcb *) + ((struct pklcd *)cons_channel)->lcd_upnext); + if (isop && isop->isop_refcnt == 1 && isop->isop_socket && + (tpcb = sototpcb(isop->isop_socket)) && + (tpcb->tp_class == TP_CLASS_0/* || == CLASS_1 */)) { + IFDEBUG(D_TPINPUT) + printf("tpinput_dt: class 0 short circuit\n"); + ENDDEBUG + dref = tpcb->tp_lref; + sref = tpcb->tp_fref; + CHECK( (tpcb->tp_refstate == REF_FREE), + E_TP_MISM_REFS,ts_inv_dref, nonx_dref, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + goto tp0_data; + } + + } +#endif + { + + CHECK( ((int)dref <= 0 || dref >= tp_refinfo.tpr_size) , + E_TP_MISM_REFS,ts_inv_dref, nonx_dref, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + CHECK( ((tpcb = tp_ref[dref].tpr_pcb ) == (struct tp_pcb *) 0 ), + E_TP_MISM_REFS,ts_inv_dref, nonx_dref, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + CHECK( (tpcb->tp_refstate == REF_FREE), + E_TP_MISM_REFS,ts_inv_dref, nonx_dref, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + } + + IFDEBUG(D_TPINPUT) + printf("HAVE A TPCB 2: 0x%x\n", tpcb); + ENDDEBUG + + /* causes a DR to be sent for CC; ER for all else */ + CHECK( (tpcb->tp_refstate == REF_FROZEN), + (dutype == CC_TPDU_type?E_TP_NO_SESSION:E_TP_MISM_REFS), + ts_inv_dref, respond, + (1 + 2 + (caddr_t)&hdr->_tpduf - (caddr_t)hdr)) + + IFDEBUG(D_TPINPUT) + printf("state of dref %d ok, tpcb 0x%x\n", dref,tpcb); + ENDDEBUG + /* + * At this point the state of the dref could be + * FROZEN: tpr_pcb == NULL, has ( reference only) timers + * for example, DC may arrive after the close() has detached + * the tpcb (e.g., if user turned off SO_LISTEN option) + * OPENING : a tpcb exists but no timers yet + * OPEN : tpcb exists & timers are outstanding + */ + + if (!tpcb->tp_cebit_off) + CONG_UPDATE_SAMPLE(tpcb, ce_bit); + + dusize = tpcb->tp_tpdusize; + pdusize = tpcb->tp_ptpdusize; + + dutype = hdr->tpdu_type << 8; /* for the switch below */ + + WHILE_OPTIONS(P, hdr, tpcb->tp_xtd_format) /* { */ + +#define caseof(x,y) case (((x)<<8)+(y)) + switch( dutype | vbptr(P)->tpv_code ) { + + caseof( CC_TPDU_type, TPP_addl_opt ): + /* not in class 0; 1 octet */ + vb_getval(P, u_char, addlopt); + break; + caseof( CC_TPDU_type, TPP_tpdu_size ): + { + u_char odusize = dusize; + vb_getval(P, u_char, dusize); + CHECK( (dusize < TP_MIN_TPDUSIZE || + dusize > TP_MAX_TPDUSIZE || dusize > odusize), + E_TP_INV_PVAL, ts_inv_pval, respond, + (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) + IFDEBUG(D_TPINPUT) + printf("CC dusize 0x%x\n", dusize); + ENDDEBUG + } + break; + caseof( CC_TPDU_type, TPP_ptpdu_size ): + { + u_short opdusize = pdusize; + switch (vbptr(P)->tpv_len) { + case 1: pdusize = vbval(P, u_char); break; + case 2: pdusize = ntohs(vbval(P, u_short)); break; + default: ; + IFDEBUG(D_TPINPUT) + printf("malformed prefered TPDU option\n"); + ENDDEBUG + } + CHECK( (pdusize == 0 || + (opdusize && (pdusize > opdusize))), + E_TP_INV_PVAL, ts_inv_pval, respond, + (1 + (caddr_t)&vbptr(P)->tpv_val - (caddr_t)hdr) ) + } + break; + caseof( CC_TPDU_type, TPP_calling_sufx): + IFDEBUG(D_TPINPUT) + printf("CC calling (local) sufxlen 0x%x\n", lsufxlen); + ENDDEBUG + lsufxloc = (caddr_t) &vbptr(P)->tpv_val; + lsufxlen = vbptr(P)->tpv_len; + break; + caseof( CC_TPDU_type, TPP_acktime ): + /* class 4 only, 2 octets */ + vb_getval(P, u_short, acktime); + acktime = ntohs(acktime); + acktime = acktime/500; /* convert to slowtimo ticks */ + if( (short)acktime <=0 ) + acktime = 2; + break; + caseof( CC_TPDU_type, TPP_called_sufx): + fsufxloc = (caddr_t) &vbptr(P)->tpv_val; + fsufxlen = vbptr(P)->tpv_len; + IFDEBUG(D_TPINPUT) + printf("CC called (foreign) sufx len %d\n", fsufxlen); + ENDDEBUG + break; + + caseof( CC_TPDU_type, TPP_checksum): + caseof( DR_TPDU_type, TPP_checksum): + caseof( DT_TPDU_type, TPP_checksum): + caseof( XPD_TPDU_type, TPP_checksum): + if( tpcb->tp_use_checksum ) { + CHECK( iso_check_csum(m, tpdu_len), + E_TP_INV_PVAL, ts_bad_csum, discard, 0) + } + break; + + /* this is different from the above because in the context + * of concat/ sep tpdu_len might not be the same as hdr len + */ + caseof( AK_TPDU_type, TPP_checksum): + caseof( XAK_TPDU_type, TPP_checksum): + caseof( DC_TPDU_type, TPP_checksum): + if( tpcb->tp_use_checksum ) { + CHECK( iso_check_csum(m, (int)hdr->tpdu_li + 1), + E_TP_INV_PVAL, ts_bad_csum, discard, 0) + } + break; +#ifdef notdef + caseof( DR_TPDU_type, TPP_addl_info ): + /* ignore - its length and meaning are + * user defined and there's no way + * to pass this info to the user anyway + */ + break; +#endif /* notdef */ + + caseof( AK_TPDU_type, TPP_subseq ): + /* used after reduction of window */ + vb_getval(P, u_short, subseq); + subseq = ntohs(subseq); + IFDEBUG(D_ACKRECV) + printf("AK dref 0x%x Subseq 0x%x\n", dref, subseq); + ENDDEBUG + break; + + caseof( AK_TPDU_type, TPP_flow_cntl_conf ): + { + u_int ylwe; + u_short ysubseq, ycredit; + + fcc_present = TRUE; + vb_getval(P, u_int, ylwe); + vb_getval(P, u_short, ysubseq); + vb_getval(P, u_short, ycredit); + ylwe = ntohl(ylwe); + ysubseq = ntohs(ysubseq); + ycredit = ntohs(ycredit); + IFDEBUG(D_ACKRECV) + printf("%s%x, subseq 0x%x, cdt 0x%x dref 0x%x\n", + "AK FCC lwe 0x", ylwe, ysubseq, ycredit, dref); + ENDDEBUG + } + break; + + default: + IFDEBUG(D_TPINPUT) + printf("param ignored dutype 0x%x, code 0x%x\n", + dutype, vbptr(P)->tpv_code); + ENDDEBUG + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "param ignored dutype code ", + dutype, vbptr(P)->tpv_code ,0,0); + ENDTRACE + IncStat(ts_param_ignored); + break; +#undef caseof + } + /* } */ END_WHILE_OPTIONS(P) + + /* NOTE: the variable dutype has been shifted left! */ + + switch( hdr->tpdu_type ) { + case CC_TPDU_type: + /* If CC comes back with an unacceptable class + * respond with a DR or ER + */ + + opt = hdr->tpdu_CCoptions; /* 1 byte */ + + { + tpp = tpcb->_tp_param; + tpp.p_class = (1<<hdr->tpdu_CCclass); + tpp.p_tpdusize = dusize; + tpp.p_ptpdusize = pdusize; + tpp.p_dont_change_params = 0; + tpp.p_xtd_format = (opt & TPO_XTD_FMT) == TPO_XTD_FMT; + tpp.p_xpd_service = (addlopt & TPAO_USE_TXPD) == TPAO_USE_TXPD; + tpp.p_use_checksum = (addlopt & TPAO_NO_CSUM) == 0; +#ifdef notdef + tpp.p_use_efc = (opt & TPO_USE_EFC) == TPO_USE_EFC; + tpp.p_use_nxpd = (addlopt & TPAO_USE_NXPD) == TPAO_USE_NXPD; + tpp.p_use_rcc = (addlopt & TPAO_USE_RCC) == TPAO_USE_RCC; +#endif /* notdef */ + + CHECK( + tp_consistency(tpcb, TP_FORCE, &tpp) != 0, + E_TP_NEGOT_FAILED, ts_negotfailed, respond, + (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) + /* ^ more or less the location of class */ + ) + IFTRACE(D_CONN) + tptrace(TPPTmisc, + "after 1 consist class, out, tpconsout", + tpcb->tp_class, dgout_routine, tpcons_output, 0 + ); + ENDTRACE + CHECK( + ((class_to_use == TP_CLASS_0)&& + (dgout_routine != tpcons_output)), + E_TP_NEGOT_FAILED, ts_negotfailed, respond, + (1 + 2 + (caddr_t)&hdr->_tpdufr.CRCC - (caddr_t)hdr) + /* ^ more or less the location of class */ + ) +#ifdef TPCONS + if (tpcb->tp_netservice == ISO_CONS && + class_to_use == TP_CLASS_0) { + struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + struct pklcd *lcp = (struct pklcd *)isop->isop_chan; + lcp->lcd_flags &= ~X25_DG_CIRCUIT; + } +#endif + } + if( ! tpcb->tp_use_checksum) + IncStat(ts_csum_off); + if(tpcb->tp_xpd_service) + IncStat(ts_use_txpd); + if(tpcb->tp_xtd_format) + IncStat(ts_xtd_fmt); + + IFTRACE(D_CONN) + tptrace(TPPTmisc, "after CC class flags dusize CCclass", + tpcb->tp_class, tpcb->tp_flags, tpcb->tp_tpdusize, + hdr->tpdu_CCclass); + ENDTRACE + + /* if called or calling suffices appeared on the CC, + * they'd better jive with what's in the pcb + */ + if( fsufxlen ) { + CHECK( ((tpcb->tp_fsuffixlen != fsufxlen) || + bcmp(fsufxloc, tpcb->tp_fsuffix, fsufxlen)), + E_TP_INV_PVAL,ts_inv_sufx, respond, + (1+fsufxloc - (caddr_t)hdr)) + } + if( lsufxlen ) { + CHECK( ((tpcb->tp_lsuffixlen != lsufxlen) || + bcmp(lsufxloc, tpcb->tp_lsuffix, lsufxlen)), + E_TP_INV_PVAL,ts_inv_sufx, respond, + (1+lsufxloc - (caddr_t)hdr)) + } + + e.ATTR(CC_TPDU).e_sref = sref; + e.ATTR(CC_TPDU).e_cdt = hdr->tpdu_CCcdt; + takes_data = TRUE; + e.ev_number = CC_TPDU; + IncStat(ts_CC_rcvd); + break; + + case DC_TPDU_type: + if (sref != tpcb->tp_fref) + printf("INPUT: inv sufx DCsref 0x%x, tp_fref 0x%x\n", + sref, tpcb->tp_fref); + + CHECK( (sref != tpcb->tp_fref), + E_TP_MISM_REFS, ts_inv_sufx, discard, + (1 + (caddr_t)&hdr->tpdu_DCsref - (caddr_t)hdr)) + + e.ev_number = DC_TPDU; + IncStat(ts_DC_rcvd); + break; + + case DR_TPDU_type: + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "DR recvd", hdr->tpdu_DRreason, 0, 0, 0); + ENDTRACE + if (sref != tpcb->tp_fref) { + printf("INPUT: inv sufx DRsref 0x%x tp_fref 0x%x\n", + sref, tpcb->tp_fref); + } + + CHECK( (sref != 0 && sref != tpcb->tp_fref && + tpcb->tp_state != TP_CRSENT), + (TP_ERROR_SNDC | E_TP_MISM_REFS),ts_inv_sufx, respond, + (1 + (caddr_t)&hdr->tpdu_DRsref - (caddr_t)hdr)) + + e.ATTR(DR_TPDU).e_reason = hdr->tpdu_DRreason; + e.ATTR(DR_TPDU).e_sref = (u_short)sref; + takes_data = TRUE; + e.ev_number = DR_TPDU; + IncStat(ts_DR_rcvd); + break; + + case ER_TPDU_type: + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "ER recvd", hdr->tpdu_ERreason,0,0,0); + ENDTRACE + e.ev_number = ER_TPDU; + e.ATTR(ER_TPDU).e_reason = hdr->tpdu_ERreason; + IncStat(ts_ER_rcvd); + break; + + case AK_TPDU_type: + + e.ATTR(AK_TPDU).e_subseq = subseq; + e.ATTR(AK_TPDU).e_fcc_present = fcc_present; + + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); + e.ATTR(AK_TPDU).e_seq = seqeotX.s_seq; + e.ATTR(AK_TPDU).e_cdt = ntohs(hdr->tpdu_AKcdtX); +#else + e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdtX; + e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseqX; +#endif /* BYTE_ORDER */ + } else { + e.ATTR(AK_TPDU).e_cdt = hdr->tpdu_AKcdt; + e.ATTR(AK_TPDU).e_seq = hdr->tpdu_AKseq; + } + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "AK recvd seq cdt subseq fcc_pres", + e.ATTR(AK_TPDU).e_seq, e.ATTR(AK_TPDU).e_cdt, + subseq, fcc_present); + ENDTRACE + + e.ev_number = AK_TPDU; + IncStat(ts_AK_rcvd); + IncPStat(tpcb, tps_AK_rcvd); + break; + + case XAK_TPDU_type: + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); + e.ATTR(XAK_TPDU).e_seq = seqeotX.s_seq; +#else + e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseqX; +#endif /* BYTE_ORDER */ + } else { + e.ATTR(XAK_TPDU).e_seq = hdr->tpdu_XAKseq; + } + e.ev_number = XAK_TPDU; + IncStat(ts_XAK_rcvd); + IncPStat(tpcb, tps_XAK_rcvd); + break; + + case XPD_TPDU_type: + if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); + e.ATTR(XPD_TPDU).e_seq = seqeotX.s_seq; +#else + e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseqX; +#endif /* BYTE_ORDER */ + } else { + e.ATTR(XPD_TPDU).e_seq = hdr->tpdu_XPDseq; + } + takes_data = TRUE; + e.ev_number = XPD_TPDU; + IncStat(ts_XPD_rcvd); + IncPStat(tpcb, tps_XPD_rcvd); + break; + + case DT_TPDU_type: + { /* the y option will cause occasional packets to be dropped. + * A little crude but it works. + */ + + IFDEBUG(D_DROP) + if(time.tv_usec & 0x4 && hdr->tpdu_DTseq & 0x1) { + IncStat(ts_ydebug); + goto discard; + } + ENDDEBUG + } + if (tpcb->tp_class == TP_CLASS_0) { + tp0_data: + e.ATTR(DT_TPDU).e_seq = 0; /* actually don't care */ + e.ATTR(DT_TPDU).e_eot = (((struct tp0du *)hdr)->tp0du_eot); + } else if (tpcb->tp_xtd_format) { +#ifdef BYTE_ORDER + union seq_type seqeotX; + + seqeotX.s_seqeot = ntohl(hdr->tpdu_seqeotX); + e.ATTR(DT_TPDU).e_seq = seqeotX.s_seq; + e.ATTR(DT_TPDU).e_eot = seqeotX.s_eot; +#else + e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseqX; + e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeotX; +#endif /* BYTE_ORDER */ + } else { + e.ATTR(DT_TPDU).e_seq = hdr->tpdu_DTseq; + e.ATTR(DT_TPDU).e_eot = hdr->tpdu_DTeot; + } + if(e.ATTR(DT_TPDU).e_eot) + IncStat(ts_eot_input); + takes_data = TRUE; + e.ev_number = DT_TPDU; + IncStat(ts_DT_rcvd); + IncPStat(tpcb, tps_DT_rcvd); + break; + + case GR_TPDU_type: + tp_indicate(T_DISCONNECT, tpcb, ECONNABORTED); + /* drop through */ + default: + /* this should NEVER happen because there is a + * check for dutype well above here + */ + error = E_TP_INV_TPDU; /* causes an ER */ + IFDEBUG(D_TPINPUT) + printf("INVALID dutype 0x%x\n", hdr->tpdu_type); + ENDDEBUG + IncStat(ts_inv_dutype); + goto respond; + } + } + /* peel off the tp header; + * remember that the du_li doesn't count itself. + * This may leave us w/ an empty mbuf at the front of a chain. + * We can't just throw away the empty mbuf because hdr still points + * into the mbuf's data area and we're still using hdr (the tpdu header) + */ + m->m_len -= ((int)hdr->tpdu_li + 1); + m->m_data += ((int)hdr->tpdu_li + 1); + + if (takes_data) { + int max = tpdu_info[ hdr->tpdu_type ] [TP_MAX_DATA_INDEX]; + int datalen = tpdu_len - hdr->tpdu_li - 1, mbtype = MT_DATA; + struct { + struct tp_disc_reason dr; + struct cmsghdr x_hdr; + } x; +#define c_hdr x.x_hdr + register struct mbuf *n; + + CHECK( (max && datalen > max), E_TP_LENGTH_INVAL, + ts_inv_length, respond, (max + hdr->tpdu_li + 1) ); + switch( hdr->tpdu_type ) { + + case CR_TPDU_type: + c_hdr.cmsg_type = TPOPT_CONN_DATA; + goto make_control_msg; + + case CC_TPDU_type: + c_hdr.cmsg_type = TPOPT_CFRM_DATA; + goto make_control_msg; + + case DR_TPDU_type: + x.dr.dr_hdr.cmsg_len = sizeof(x) - sizeof(c_hdr); + x.dr.dr_hdr.cmsg_type = TPOPT_DISC_REASON; + x.dr.dr_hdr.cmsg_level = SOL_TRANSPORT; + x.dr.dr_reason = hdr->tpdu_DRreason; + c_hdr.cmsg_type = TPOPT_DISC_DATA; + make_control_msg: + datalen += sizeof(c_hdr); + c_hdr.cmsg_len = datalen; + c_hdr.cmsg_level = SOL_TRANSPORT; + mbtype = MT_CONTROL; + MGET(n, M_DONTWAIT, MT_DATA); + if (n == 0) + {m_freem(m); m = 0; datalen = 0; goto invoke; } + if (hdr->tpdu_type == DR_TPDU_type) { + datalen += sizeof(x) - sizeof(c_hdr); + bcopy((caddr_t)&x, mtod(n, caddr_t), n->m_len = sizeof(x)); + } else + bcopy((caddr_t)&c_hdr, mtod(n, caddr_t), + n->m_len = sizeof(c_hdr)); + n->m_next = m; + m = n; + /* FALLTHROUGH */ + + case XPD_TPDU_type: + if (mbtype != MT_CONTROL) + mbtype = MT_OOBDATA; + m->m_flags |= M_EOR; + /* FALLTHROUGH */ + + case DT_TPDU_type: + for (n = m; n; n = n->m_next) { + MCHTYPE(n, mbtype); + } + invoke: + e.ATTR(DT_TPDU).e_datalen = datalen; + e.ATTR(DT_TPDU).e_data = m; + break; + + default: + printf( + "ERROR in tp_input! hdr->tpdu_type 0x%x takes_data 0x%x m 0x%x\n", + hdr->tpdu_type, takes_data, m); + break; + } + /* prevent m_freem() after tp_driver() from throwing it all away */ + m = MNULL; + } + + IncStat(ts_tpdu_rcvd); + + IFDEBUG(D_TPINPUT) + printf( "tp_input: before driver, state 0x%x event 0x%x m 0x%x", + tpcb->tp_state, e.ev_number, m ); + printf(" e.e_data 0x%x\n", e.ATTR(DT_TPDU).e_data); + printf("takes_data 0x%x m_len 0x%x, tpdu_len 0x%x\n", + takes_data, (m==MNULL)?0:m->m_len, tpdu_len); + ENDDEBUG + + error = tp_driver(tpcb, &e); + + ASSERT(tpcb != (struct tp_pcb *)0); + ASSERT(tpcb->tp_sock != (struct socket *)0); + if( tpcb->tp_sock->so_error == 0 ) + tpcb->tp_sock->so_error = error; + + /* Kludge to keep the state tables under control (adding + * data on connect & disconnect & freeing the mbuf containing + * the data would have exploded the tables and made a big mess ). + */ + switch(e.ev_number) { + case CC_TPDU: + case DR_TPDU: + case CR_TPDU: + m = e.ATTR(CC_TPDU).e_data; /* same field for all three dutypes */ + IFDEBUG(D_TPINPUT) + printf("after driver, restoring m to 0x%x, takes_data 0x%x\n", + m, takes_data); + ENDDEBUG + break; + default: + break; + } + /* Concatenated sequences are terminated by any tpdu that + * carries data: CR, CC, DT, XPD, DR. + * All other tpdu types may be concatenated: AK, XAK, DC, ER. + */ + +separate: + if ( takes_data == 0 ) { + ASSERT( m != MNULL ); + /* + * we already peeled off the prev. tp header so + * we can just pull up some more and repeat + */ + + if( m = tp_inputprep(m) ) { + IFDEBUG(D_TPINPUT) + hdr = mtod(m, struct tpdu *); + printf("tp_input @ separate: hdr 0x%x size %d m 0x%x\n", + hdr, (int) hdr->tpdu_li + 1, m); + dump_mbuf(m, "tp_input after driver, at separate"); + ENDDEBUG + + IncStat(ts_concat_rcvd); + goto again; + } + } + if ( m != MNULL ) { + IFDEBUG(D_TPINPUT) + printf("tp_input : m_freem(0x%x)\n", m); + ENDDEBUG + m_freem(m); + IFDEBUG(D_TPINPUT) + printf("tp_input : after m_freem 0x%x\n", m); + ENDDEBUG + } + return (ProtoHook) tpcb; + +discard: + /* class 4: drop the tpdu */ + /* class 2,0: Should drop the net connection, if you can figure out + * to which connection it applies + */ + IFDEBUG(D_TPINPUT) + printf("tp_input DISCARD\n"); + ENDDEBUG + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "tp_input DISCARD m", m,0,0,0); + ENDTRACE + m_freem(m); + IncStat(ts_recv_drop); + return (ProtoHook)0; + +nonx_dref: + switch (dutype) { + default: + goto discard; + case CC_TPDU_type: + /* error = E_TP_MISM_REFS; */ + break; + case DR_TPDU_type: + error |= TP_ERROR_SNDC; + } +respond: + IFDEBUG(D_TPINPUT) + printf("RESPOND: error 0x%x, errlen 0x%x\n", error, errlen); + ENDDEBUG + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "tp_input RESPOND m error sref", m, error, sref, 0); + ENDTRACE + if (sref == 0) + goto discard; + (void) tp_error_emit(error, (u_long)sref, (struct sockaddr_iso *)faddr, + (struct sockaddr_iso *)laddr, m, errlen, tpcb, + cons_channel, dgout_routine); + IFDEBUG(D_ERROR_EMIT) + printf("tp_input after error_emit\n"); + ENDDEBUG + +#ifdef lint + printf("",sref,opt); +#endif /* lint */ + IncStat(ts_recv_drop); + return (ProtoHook)0; +} + + +/* + * NAME: tp_headersize() + * + * CALLED FROM: + * tp_emit() and tp_sbsend() + * TP needs to know the header size so it can figure out how + * much data to put in each tpdu. + * + * FUNCTION, ARGUMENTS, and RETURN VALUE: + * For a given connection, represented by (tpcb), and + * tpdu type (dutype), return the size of a tp header. + * + * RETURNS: the expected size of the heade in bytesr + * + * SIDE EFFECTS: + * + * NOTES: It would be nice if it got the network header size as well. + */ +int +tp_headersize(dutype, tpcb) + int dutype; + struct tp_pcb *tpcb; +{ + register int size = 0; + + IFTRACE(D_CONN) + tptrace(TPPTmisc, "tp_headersize dutype class xtd_format", + dutype, tpcb->tp_class, tpcb->tp_xtd_format, 0); + ENDTRACE + if( !( (tpcb->tp_class == TP_CLASS_0) || + (tpcb->tp_class == TP_CLASS_4) || + (dutype == DR_TPDU_type) || + (dutype == CR_TPDU_type) )) { + printf("tp_headersize:dutype 0x%x, class 0x%x", + dutype, tpcb->tp_class); + /* TODO: identify this and GET RID OF IT */ + } + ASSERT( (tpcb->tp_class == TP_CLASS_0) || + (tpcb->tp_class == TP_CLASS_4) || + (dutype == DR_TPDU_type) || + (dutype == CR_TPDU_type) ); + + if( tpcb->tp_class == TP_CLASS_0 ) { + size = tpdu_info[ dutype ] [TP_LEN_CLASS_0_INDEX]; + } else { + size = tpdu_info[ dutype ] [tpcb->tp_xtd_format]; + } + return size; + /* caller must get network level header size separately */ +} diff --git a/sys/netiso/tp_ip.h b/sys/netiso/tp_ip.h new file mode 100644 index 0000000..f277767 --- /dev/null +++ b/sys/netiso/tp_ip.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_ip.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_ip.h,v 5.1 88/10/12 12:19:47 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_ip.h,v $ + * + * internet IP-dependent structures and include files + * + */ + + +#ifndef __TP_IP__ +#define __TP_IP__ + +#ifndef SOCK_STREAM +#include <sys/socket.h> +#endif + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <net/route.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> + + +struct inpcb tp_inpcb; + /* queue of active inpcbs for tp ; for tp with dod ip */ + +#endif /* __TP_IP__ */ diff --git a/sys/netiso/tp_iso.c b/sys/netiso/tp_iso.c new file mode 100644 index 0000000..1cf67f8 --- /dev/null +++ b/sys/netiso/tp_iso.c @@ -0,0 +1,693 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_iso.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * $Header: /var/src/sys/netiso/RCS/tp_iso.c,v 5.1 89/02/09 16:20:51 hagens Exp $ + * $Source: /var/src/sys/netiso/RCS/tp_iso.c,v $ + * + * Here is where you find the iso-dependent code. We've tried + * keep all net-level and (primarily) address-family-dependent stuff + * out of the tp source, and everthing here is reached indirectly + * through a switch table (struct nl_protosw *) tpcb->tp_nlproto + * (see tp_pcb.c). + * The routines here are: + * iso_getsufx: gets transport suffix out of an isopcb structure. + * iso_putsufx: put transport suffix into an isopcb structure. + * iso_putnetaddr: put a whole net addr into an isopcb. + * iso_getnetaddr: get a whole net addr from an isopcb. + * iso_cmpnetaddr: compare a whole net addr from an isopcb. + * iso_recycle_suffix: clear suffix for reuse in isopcb + * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff + * tpclnp_mtu: figure out what size tpdu to use + * tpclnp_input: take a pkt from clnp, strip off its clnp header, + * give to tp + * tpclnp_output_dg: package a pkt for clnp given 2 addresses & some data + * tpclnp_output: package a pkt for clnp given an isopcb & some data + */ + +#ifdef ISO + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/protosw.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netiso/argo_debug.h> +#include <netiso/tp_param.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_clnp.h> +#include <netiso/cltp_var.h> + +/* + * CALLED FROM: + * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR + * FUNCTION, ARGUMENTS: + * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. + */ + +iso_getsufx(isop, lenp, data_out, which) + struct isopcb *isop; + u_short *lenp; + caddr_t data_out; + int which; +{ + register struct sockaddr_iso *addr = 0; + + switch (which) { + case TP_LOCAL: + addr = isop->isop_laddr; + break; + + case TP_FOREIGN: + addr = isop->isop_faddr; + } + if (addr) + bcopy(TSEL(addr), data_out, (*lenp = addr->siso_tlen)); +} + +/* CALLED FROM: + * tp_newsocket(); i.e., when a connection is being established by an + * incoming CR_TPDU. + * + * FUNCTION, ARGUMENTS: + * Put a transport suffix (found in name) into an isopcb structure (isop). + * The argument (which) takes the value TP_LOCAL or TP_FOREIGN. + */ +void +iso_putsufx(isop, sufxloc, sufxlen, which) + struct isopcb *isop; + caddr_t sufxloc; + int sufxlen, which; +{ + struct sockaddr_iso **dst, *backup; + register struct sockaddr_iso *addr; + struct mbuf *m; + int len; + + switch (which) { + default: + return; + + case TP_LOCAL: + dst = &isop->isop_laddr; + backup = &isop->isop_sladdr; + break; + + case TP_FOREIGN: + dst = &isop->isop_faddr; + backup = &isop->isop_sfaddr; + } + if ((addr = *dst) == 0) { + addr = *dst = backup; + addr->siso_nlen = 0; + addr->siso_slen = 0; + addr->siso_plen = 0; + printf("iso_putsufx on un-initialized isopcb\n"); + } + len = sufxlen + addr->siso_nlen + + (sizeof(*addr) - sizeof(addr->siso_data)); + if (addr == backup) { + if (len > sizeof(*addr)) { + m = m_getclr(M_DONTWAIT, MT_SONAME); + if (m == 0) + return; + addr = *dst = mtod(m, struct sockaddr_iso *); + *addr = *backup; + m->m_len = len; + } + } + bcopy(sufxloc, TSEL(addr), sufxlen); + addr->siso_tlen = sufxlen; + addr->siso_len = len; +} + +/* + * CALLED FROM: + * tp.trans whenever we go into REFWAIT state. + * FUNCTION and ARGUMENT: + * Called when a ref is frozen, to allow the suffix to be reused. + * (isop) is the net level pcb. This really shouldn't have to be + * done in a NET level pcb but... for the internet world that just + * the way it is done in BSD... + * The alternative is to have the port unusable until the reference + * timer goes off. + */ +void +iso_recycle_tsuffix(isop) + struct isopcb *isop; +{ + isop->isop_laddr->siso_tlen = isop->isop_faddr->siso_tlen = 0; +} + +/* + * CALLED FROM: + * tp_newsocket(); i.e., when a connection is being established by an + * incoming CR_TPDU. + * + * FUNCTION and ARGUMENTS: + * Copy a whole net addr from a struct sockaddr (name). + * into an isopcb (isop). + * The argument (which) takes values TP_LOCAL or TP_FOREIGN + */ +void +iso_putnetaddr(isop, name, which) + register struct isopcb *isop; + struct sockaddr_iso *name; + int which; +{ + struct sockaddr_iso **sisop, *backup; + register struct sockaddr_iso *siso; + + switch (which) { + default: + printf("iso_putnetaddr: should panic\n"); + return; + case TP_LOCAL: + sisop = &isop->isop_laddr; + backup = &isop->isop_sladdr; + break; + case TP_FOREIGN: + sisop = &isop->isop_faddr; + backup = &isop->isop_sfaddr; + } + siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); + IFDEBUG(D_TPISO) + printf("ISO_PUTNETADDR\n"); + dump_isoaddr(isop->isop_faddr); + ENDDEBUG + siso->siso_addr = name->siso_addr; +} + +/* + * CALLED FROM: + * tp_input() when a connection is being established by an + * incoming CR_TPDU, and considered for interception. + * + * FUNCTION and ARGUMENTS: + * compare a whole net addr from a struct sockaddr (name), + * with that implicitly stored in an isopcb (isop). + * The argument (which) takes values TP_LOCAL or TP_FOREIGN. + */ +iso_cmpnetaddr(isop, name, which) + register struct isopcb *isop; + register struct sockaddr_iso *name; + int which; +{ + struct sockaddr_iso **sisop, *backup; + register struct sockaddr_iso *siso; + + switch (which) { + default: + printf("iso_cmpnetaddr: should panic\n"); + return 0; + case TP_LOCAL: + sisop = &isop->isop_laddr; + backup = &isop->isop_sladdr; + break; + case TP_FOREIGN: + sisop = &isop->isop_faddr; + backup = &isop->isop_sfaddr; + } + siso = ((*sisop == 0) ? (*sisop = backup) : *sisop); + IFDEBUG(D_TPISO) + printf("ISO_CMPNETADDR\n"); + dump_isoaddr(siso); + ENDDEBUG + if (name->siso_tlen && bcmp(TSEL(name), TSEL(siso), name->siso_tlen)) + return (0); + return (bcmp((caddr_t)name->siso_data, + (caddr_t)siso->siso_data, name->siso_nlen) == 0); +} + +/* + * CALLED FROM: + * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR + * FUNCTION and ARGUMENTS: + * Copy a whole net addr from an isopcb (isop) into + * a struct sockaddr (name). + * The argument (which) takes values TP_LOCAL or TP_FOREIGN. + */ + +void +iso_getnetaddr( isop, name, which) + struct isopcb *isop; + struct mbuf *name; + int which; +{ + struct sockaddr_iso *siso = + (which == TP_LOCAL ? isop->isop_laddr : isop->isop_faddr); + if (siso) + bcopy((caddr_t)siso, mtod(name, caddr_t), + (unsigned)(name->m_len = siso->siso_len)); + else + name->m_len = 0; +} +/* + * NAME: tpclnp_mtu() + * + * CALLED FROM: + * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT + * + * FUNCTION, ARGUMENTS, and RETURN VALUE: + * + * Perform subnetwork dependent part of determining MTU information. + * It appears that setting a double pointer to the rtentry associated with + * the destination, and returning the header size for the network protocol + * suffices. + * + * SIDE EFFECTS: + * Sets tp_routep pointer in pcb. + * + * NOTES: + */ +tpclnp_mtu(tpcb) +register struct tp_pcb *tpcb; +{ + struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + + IFDEBUG(D_CONN) + printf("tpclnp_mtu(tpcb)\n", tpcb); + ENDDEBUG + tpcb->tp_routep = &(isop->isop_route.ro_rt); + if (tpcb->tp_netservice == ISO_CONS) + return 0; + else + return (sizeof(struct clnp_fixed) + sizeof(struct clnp_segment) + + 2 * sizeof(struct iso_addr)); + +} + +/* + * CALLED FROM: + * tp_emit() + * FUNCTION and ARGUMENTS: + * Take a packet(m0) from tp and package it so that clnp will accept it. + * This means prepending space for the clnp header and filling in a few + * of the fields. + * isop is the isopcb structure; datalen is the length of the data in the + * mbuf string m0. + * RETURN VALUE: + * whatever (E*) is returned form the net layer output routine. + */ + +int +tpclnp_output(isop, m0, datalen, nochksum) + struct isopcb *isop; + struct mbuf *m0; + int datalen; + int nochksum; +{ + register struct mbuf *m = m0; + IncStat(ts_tpdu_sent); + + IFDEBUG(D_TPISO) + struct tpdu *hdr = mtod(m0, struct tpdu *); + + printf( +"abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n", + datalen, + (int)hdr->tpdu_li, (int)hdr->tpdu_type, nochksum); + dump_isoaddr(isop->isop_faddr); + printf("\nsrc addr:\n"); + dump_isoaddr(isop->isop_laddr); + dump_mbuf(m0, "at tpclnp_output"); + ENDDEBUG + + return + clnp_output(m0, isop, datalen, /* flags */nochksum ? CLNP_NO_CKSUM : 0); +} + +/* + * CALLED FROM: + * tp_error_emit() + * FUNCTION and ARGUMENTS: + * This is a copy of tpclnp_output that takes the addresses + * instead of a pcb. It's used by the tp_error_emit, when we + * don't have an iso_pcb with which to call the normal output rtn. + * RETURN VALUE: + * ENOBUFS or + * whatever (E*) is returned form the net layer output routine. + */ + +int +tpclnp_output_dg(laddr, faddr, m0, datalen, ro, nochksum) + struct iso_addr *laddr, *faddr; + struct mbuf *m0; + int datalen; + struct route *ro; + int nochksum; +{ + struct isopcb tmppcb; + int err; + int flags; + register struct mbuf *m = m0; + + IFDEBUG(D_TPISO) + printf("tpclnp_output_dg datalen 0x%x m0 0x%x\n", datalen, m0); + ENDDEBUG + + /* + * Fill in minimal portion of isopcb so that clnp can send the + * packet. + */ + bzero((caddr_t)&tmppcb, sizeof(tmppcb)); + tmppcb.isop_laddr = &tmppcb.isop_sladdr; + tmppcb.isop_laddr->siso_addr = *laddr; + tmppcb.isop_faddr = &tmppcb.isop_sfaddr; + tmppcb.isop_faddr->siso_addr = *faddr; + + IFDEBUG(D_TPISO) + printf("tpclnp_output_dg faddr: \n"); + dump_isoaddr(&tmppcb.isop_sfaddr); + printf("\ntpclnp_output_dg laddr: \n"); + dump_isoaddr(&tmppcb.isop_sladdr); + printf("\n"); + ENDDEBUG + + /* + * Do not use packet cache since this is a one shot error packet + */ + flags = (CLNP_NOCACHE|(nochksum?CLNP_NO_CKSUM:0)); + + IncStat(ts_tpdu_sent); + + err = clnp_output(m0, &tmppcb, datalen, flags); + + /* + * Free route allocated by clnp (if the route was indeed allocated) + */ + if (tmppcb.isop_route.ro_rt) + RTFREE(tmppcb.isop_route.ro_rt); + + return(err); +} +/* + * CALLED FROM: + * clnp's input routine, indirectly through the protosw. + * FUNCTION and ARGUMENTS: + * Take a packet (m) from clnp, strip off the clnp header and give it to tp + * No return value. + */ +ProtoHook +tpclnp_input(m, src, dst, clnp_len, ce_bit) + register struct mbuf *m; + struct sockaddr_iso *src, *dst; + int clnp_len, ce_bit; +{ + struct mbuf *tp_inputprep(); + int tp_input(), cltp_input(), (*input)() = tp_input; + + IncStat(ts_pkt_rcvd); + + IFDEBUG(D_TPINPUT) + printf("tpclnp_input: m 0x%x clnp_len 0x%x\n", m, clnp_len); + dump_mbuf(m, "at tpclnp_input"); + ENDDEBUG + /* + * CLNP gives us an mbuf chain WITH the clnp header pulled up, + * and the length of the clnp header. + * First, strip off the Clnp header. leave the mbuf there for the + * pullup that follows. + */ + m->m_len -= clnp_len; + m->m_data += clnp_len; + m->m_pkthdr.len -= clnp_len; + /* XXXX: should probably be in clnp_input */ + switch (dst->siso_data[dst->siso_nlen - 1]) { +#ifdef TUBA + case ISOPROTO_TCP: + return (tuba_tcpinput(m, src, dst)); +#endif + case 0: + if (m->m_len == 0 && (m = m_pullup(m, 1)) == 0) + return 0; + if (*(mtod(m, u_char *)) == ISO10747_IDRP) + return (idrp_input(m, src, dst)); + } + m = tp_inputprep(m); + if (m == 0) + return 0; + if (mtod(m, u_char *)[1] == UD_TPDU_type) + input = cltp_input; + + IFDEBUG(D_TPINPUT) + dump_mbuf(m, "after tpclnp_input both pullups"); + ENDDEBUG + + IFDEBUG(D_TPISO) + printf("calling %sinput : src 0x%x, dst 0x%x, src addr:\n", + (input == tp_input ? "tp_" : "clts_"), src, dst); + dump_isoaddr(src); + printf(" dst addr:\n"); + dump_isoaddr(dst); + ENDDEBUG + + (void) (*input)(m, (struct sockaddr *)src, (struct sockaddr *)dst, + 0, tpclnp_output_dg, ce_bit); + + IFDEBUG(D_QUENCH) + { + if(time.tv_usec & 0x4 && time.tv_usec & 0x40) { + printf("tpclnp_input: FAKING %s\n", + tp_stat.ts_pkt_rcvd & 0x1?"QUENCH":"QUENCH2"); + if(tp_stat.ts_pkt_rcvd & 0x1) { + tpclnp_ctlinput(PRC_QUENCH, &src); + } else { + tpclnp_ctlinput(PRC_QUENCH2, &src); + } + } + } + ENDDEBUG + + return 0; +} + +ProtoHook +iso_rtchange() +{ + return 0; +} + +/* + * CALLED FROM: + * tpclnp_ctlinput() + * FUNCTION and ARGUMENTS: + * find the tpcb pointer and pass it to tp_quench + */ +void +tpiso_decbit(isop) + struct isopcb *isop; +{ + tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH2); +} +/* + * CALLED FROM: + * tpclnp_ctlinput() + * FUNCTION and ARGUMENTS: + * find the tpcb pointer and pass it to tp_quench + */ +void +tpiso_quench(isop) + struct isopcb *isop; +{ + tp_quench((struct tp_pcb *)isop->isop_socket->so_pcb, PRC_QUENCH); +} + +/* + * CALLED FROM: + * The network layer through the protosw table. + * FUNCTION and ARGUMENTS: + * When clnp an ICMP-like msg this gets called. + * It either returns an error status to the user or + * it causes all connections on this address to be aborted + * by calling the appropriate xx_notify() routine. + * (cmd) is the type of ICMP error. + * (siso) is the address of the guy who sent the ER CLNPDU + */ +ProtoHook +tpclnp_ctlinput(cmd, siso) + int cmd; + struct sockaddr_iso *siso; +{ + extern u_char inetctlerrmap[]; + extern ProtoHook tpiso_abort(); + extern ProtoHook iso_rtchange(); + extern ProtoHook tpiso_reset(); + void iso_pcbnotify(); + + IFDEBUG(D_TPINPUT) + printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd); + dump_isoaddr(siso); + ENDDEBUG + + if (cmd < 0 || cmd > PRC_NCMDS) + return 0; + if (siso->siso_family != AF_ISO) + return 0; + switch (cmd) { + + case PRC_QUENCH2: + iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_decbit); + break; + + case PRC_QUENCH: + iso_pcbnotify(&tp_isopcb, siso, 0, (int (*)())tpiso_quench); + break; + + case PRC_TIMXCEED_REASS: + case PRC_ROUTEDEAD: + iso_pcbnotify(&tp_isopcb, siso, 0, tpiso_reset); + break; + + case PRC_HOSTUNREACH: + case PRC_UNREACH_NET: + case PRC_IFDOWN: + case PRC_HOSTDEAD: + iso_pcbnotify(&tp_isopcb, siso, + (int)inetctlerrmap[cmd], iso_rtchange); + break; + + default: + /* + case PRC_MSGSIZE: + case PRC_UNREACH_HOST: + case PRC_UNREACH_PROTOCOL: + case PRC_UNREACH_PORT: + case PRC_UNREACH_NEEDFRAG: + case PRC_UNREACH_SRCFAIL: + case PRC_REDIRECT_NET: + case PRC_REDIRECT_HOST: + case PRC_REDIRECT_TOSNET: + case PRC_REDIRECT_TOSHOST: + case PRC_TIMXCEED_INTRANS: + case PRC_PARAMPROB: + */ + iso_pcbnotify(&tp_isopcb, siso, (int)inetctlerrmap[cmd], tpiso_abort); + break; + } + return 0; +} +/* + * XXX - Variant which is called by clnp_er.c with an isoaddr rather + * than a sockaddr_iso. + */ + +static struct sockaddr_iso siso = {sizeof(siso), AF_ISO}; +tpclnp_ctlinput1(cmd, isoa) + int cmd; + struct iso_addr *isoa; +{ + bzero((caddr_t)&siso.siso_addr, sizeof(siso.siso_addr)); + bcopy((caddr_t)isoa, (caddr_t)&siso.siso_addr, isoa->isoa_len); + tpclnp_ctlinput(cmd, &siso); +} + +/* + * These next 2 routines are + * CALLED FROM: + * xxx_notify() from tp_ctlinput() when + * net level gets some ICMP-equiv. type event. + * FUNCTION and ARGUMENTS: + * Cause the connection to be aborted with some sort of error + * reason indicating that the network layer caused the abort. + * Fakes an ER TPDU so we can go through the driver. + * abort always aborts the TP connection. + * reset may or may not, depending on the TP class that's in use. + */ +ProtoHook +tpiso_abort(isop) + struct isopcb *isop; +{ + struct tp_event e; + + IFDEBUG(D_CONN) + printf("tpiso_abort 0x%x\n", isop); + ENDDEBUG + e.ev_number = ER_TPDU; + e.ATTR(ER_TPDU).e_reason = ECONNABORTED; + return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e); +} + +ProtoHook +tpiso_reset(isop) + struct isopcb *isop; +{ + struct tp_event e; + + e.ev_number = T_NETRESET; + return tp_driver((struct tp_pcb *)isop->isop_socket->so_pcb, &e); + +} + +#endif /* ISO */ diff --git a/sys/netiso/tp_meas.c b/sys/netiso/tp_meas.c new file mode 100644 index 0000000..f8bbbe6 --- /dev/null +++ b/sys/netiso/tp_meas.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_meas.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * $Header: tp_meas.c,v 5.2 88/11/18 17:28:04 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_meas.c,v $ + * + * tp_meas.c : create a performance measurement event + * in the circular buffer tp_Meas[] + */ + +#include <sys/types.h> +#include <sys/time.h> + +#include <netiso/argo_debug.h> +#include <netiso/tp_meas.h> + +extern struct timeval time; + +#ifdef TP_PERF_MEAS +int tp_Measn = 0; +struct tp_Meas tp_Meas[TPMEASN]; + +/* + * NAME: tpmeas() + * + * CALLED FROM: tp_emit(), tp_soisdisconecting(), tp_soisdisconnected() + * tp0_stash(), tp_stash(), tp_send(), tp_goodack(), tp_usrreq() + * + * FUNCTION and ARGUMENTS: + * stashes a performance-measurement event for the given reference (ref) + * (kind) tells which kind of event, timev is the time to be stored + * with this event, (seq), (win), and (size) are integers that usually + * refer to the sequence number, window number (on send) and + * size of tpdu or window. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +Tpmeas(ref, kind, timev, seq, win, size) + u_int ref; + u_int kind; + struct timeval *timev; + u_int seq, win, size; +{ + register struct tp_Meas *tpm; + static int mseq; + + tpm = &tp_Meas[tp_Measn++]; + tp_Measn %= TPMEASN; + + tpm->tpm_kind = kind; + tpm->tpm_tseq = mseq++; + tpm->tpm_ref = ref; + if(kind == TPtime_from_ll) + bcopy((caddr_t)timev, (caddr_t)&tpm->tpm_time, sizeof(struct timeval)); + else + bcopy( (caddr_t)&time, + (caddr_t)&tpm->tpm_time, sizeof(struct timeval) ); + tpm->tpm_seq = seq; + tpm->tpm_window = win; + tpm->tpm_size = size; +} + +#endif /* TP_PERF_MEAS */ diff --git a/sys/netiso/tp_meas.h b/sys/netiso/tp_meas.h new file mode 100644 index 0000000..10ef93d --- /dev/null +++ b/sys/netiso/tp_meas.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_meas.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +#ifdef TP_PERF_MEAS +#define tpmeas(a, b, t, c, d, e) \ + Tpmeas((u_int)(a), (u_int)(b), t, (u_int)(c), (u_int)(d), (u_int)(e)) + +struct tp_Meas { + int tpm_tseq; + u_char tpm_kind; + u_short tpm_ref; + u_short tpm_size; + u_short tpm_window; + u_int tpm_seq; + struct timeval tpm_time; +}; + +#define TPMEASN 4000 +extern int tp_Measn; +extern struct tp_Meas tp_Meas[]; + +/* + * the kinds of events for packet tracing are: + */ +#define TPtime_from_session 0x01 +#define TPtime_to_session 0x02 +#define TPtime_ack_rcvd 0x03 +#define TPtime_ack_sent 0x04 +#define TPtime_from_ll 0x05 +#define TPtime_to_ll 0x06 +#define TPsbsend 0x07 +#define TPtime_open 0x08 +#define TPtime_open_X 0x28 /* xtd format */ +#define TPtime_close 0x09 + +#endif /* TP_PERF_MEAS */ diff --git a/sys/netiso/tp_output.c b/sys/netiso/tp_output.c new file mode 100644 index 0000000..cdd7c4f --- /dev/null +++ b/sys/netiso/tp_output.c @@ -0,0 +1,712 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_output.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_output.c,v 5.4 88/11/18 17:28:08 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_output.c,v $ + * + * In here is tp_ctloutput(), the guy called by [sg]etsockopt(), + */ + +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/systm.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <netiso/tp_param.h> +#include <netiso/tp_user.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_ip.h> +#include <netiso/tp_clnp.h> +#include <netiso/tp_timer.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_trace.h> + +#define TPDUSIZESHIFT 24 +#define CLASSHIFT 16 + +/* + * NAME: tp_consistency() + * + * CALLED FROM: + * tp_ctloutput(), tp_input() + * + * FUNCTION and ARGUMENTS: + * Checks the consistency of options and tpdusize with class, + * using the parameters passed in via (param). + * (cmd) may be TP_STRICT or TP_FORCE or both. + * Force means it will set all the values in (tpcb) to those in + * the input arguements iff no errors were encountered. + * Strict means that no inconsistency will be tolerated. If it's + * not used, checksum and tpdusize inconsistencies will be tolerated. + * The reason for this is that in some cases, when we're negotiating down + * from class 4, these options should be changed but should not + * cause negotiation to fail. + * + * RETURNS + * E* or EOK + * E* if the various parms aren't ok for a given class + * EOK if they are ok for a given class + */ + +int +tp_consistency( tpcb, cmd, param ) + u_int cmd; + struct tp_conn_param *param; + struct tp_pcb *tpcb; +{ + register int error = EOK; + int class_to_use = tp_mask_to_num(param->p_class); + + IFTRACE(D_SETPARAMS) + tptrace(TPPTmisc, + "tp_consist enter class_to_use dontchange param.class cmd", + class_to_use, param->p_dont_change_params, param->p_class, cmd); + ENDTRACE + IFDEBUG(D_SETPARAMS) + printf("tp_consistency %s %s\n", + cmd& TP_FORCE? "TP_FORCE": "", + cmd& TP_STRICT? "TP_STRICT":""); + ENDDEBUG + if ((cmd & TP_FORCE) && (param->p_dont_change_params)) { + cmd &= ~TP_FORCE; + } + /* can switch net services within a domain, but + * cannot switch domains + */ + switch( param->p_netservice) { + case ISO_CONS: + case ISO_CLNS: + case ISO_COSNS: + /* param->p_netservice in ISO DOMAIN */ + if(tpcb->tp_domain != AF_ISO ) { + error = EINVAL; goto done; + } + break; + case IN_CLNS: + /* param->p_netservice in INET DOMAIN */ + if( tpcb->tp_domain != AF_INET ) { + error = EINVAL; goto done; + } + break; + /* no others not possible-> netservice is a 2-bit field! */ + } + + IFDEBUG(D_SETPARAMS) + printf("p_class 0x%x, class_to_use 0x%x\n", param->p_class, + class_to_use); + ENDDEBUG + if((param->p_netservice < 0) || (param->p_netservice > TP_MAX_NETSERVICES)){ + error = EINVAL; goto done; + } + if( (param->p_class & TP_CLASSES_IMPLEMENTED) == 0 ) { + error = EINVAL; goto done; + } + IFDEBUG(D_SETPARAMS) + printf("Nretrans 0x%x\n", param->p_Nretrans ); + ENDDEBUG + if( ( param->p_Nretrans < 1 ) || + (param->p_cr_ticks < 1) || (param->p_cc_ticks < 1) ) { + /* bad for any class because negot has to be done a la class 4 */ + error = EINVAL; goto done; + } + IFDEBUG(D_SETPARAMS) + printf("use_csum 0x%x\n", param->p_use_checksum ); + printf("xtd_format 0x%x\n", param->p_xtd_format ); + printf("xpd_service 0x%x\n", param->p_xpd_service ); + printf("tpdusize 0x%x\n", param->p_tpdusize ); + printf("tpcb->flags 0x%x\n", tpcb->tp_flags ); + ENDDEBUG + switch( class_to_use ) { + + case 0: + /* do not use checksums, xtd format, or XPD */ + + if( param->p_use_checksum | param->p_xtd_format | param->p_xpd_service ) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_use_checksum = 0; + param->p_xtd_format = 0; + param->p_xpd_service = 0; + } + break; + } + + if (param->p_tpdusize < TP_MIN_TPDUSIZE) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_tpdusize = TP_MIN_TPDUSIZE; + } + break; + } + if (param->p_tpdusize > TP0_TPDUSIZE) { + if (cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_tpdusize = TP0_TPDUSIZE; + } + break; + } + + /* connect/disc data not allowed for class 0 */ + if (tpcb->tp_ucddata) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else if(cmd & TP_FORCE) { + m_freem(tpcb->tp_ucddata); + tpcb->tp_ucddata = 0; + } + } + break; + + case 4: + IFDEBUG(D_SETPARAMS) + printf("dt_ticks 0x%x\n", param->p_dt_ticks ); + printf("x_ticks 0x%x\n", param->p_x_ticks ); + printf("dr_ticks 0x%x\n", param->p_dr_ticks ); + printf("keepalive 0x%x\n", param->p_keepalive_ticks ); + printf("sendack 0x%x\n", param->p_sendack_ticks ); + printf("inact 0x%x\n", param->p_inact_ticks ); + printf("ref 0x%x\n", param->p_ref_ticks ); + ENDDEBUG + if( (param->p_class & TP_CLASS_4 ) && ( + (param->p_dt_ticks < 1) || (param->p_dr_ticks < 1) || + (param->p_x_ticks < 1) || (param->p_keepalive_ticks < 1) || + (param->p_sendack_ticks < 1) || (param->p_ref_ticks < 1) || + (param->p_inact_ticks < 1) ) ) { + error = EINVAL; + break; + } + IFDEBUG(D_SETPARAMS) + printf("rx_strat 0x%x\n", param->p_rx_strat ); + ENDDEBUG + if(param->p_rx_strat > + ( TPRX_USE_CW | TPRX_EACH | TPRX_FASTSTART) ) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_rx_strat = TPRX_USE_CW; + } + break; + } + IFDEBUG(D_SETPARAMS) + printf("ack_strat 0x%x\n", param->p_ack_strat ); + ENDDEBUG + if((param->p_ack_strat != 0) && (param->p_ack_strat != 1)) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_ack_strat = TPACK_WINDOW; + } + break; + } + if (param->p_tpdusize < TP_MIN_TPDUSIZE) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_tpdusize = TP_MIN_TPDUSIZE; + } + break; + } + if (param->p_tpdusize > TP_TPDUSIZE) { + if(cmd & TP_STRICT) { + error = EINVAL; + } else { + param->p_tpdusize = TP_TPDUSIZE; + } + break; + } + break; + } + + if ((error==0) && (cmd & TP_FORCE)) { + long dusize = ((long)param->p_ptpdusize) << 7; + /* Enforce Negotation rules below */ + tpcb->tp_class = param->p_class; + if (tpcb->tp_use_checksum || param->p_use_checksum) + tpcb->tp_use_checksum = 1; + if (!tpcb->tp_xpd_service || !param->p_xpd_service) + tpcb->tp_xpd_service = 0; + if (!tpcb->tp_xtd_format || !param->p_xtd_format) + tpcb->tp_xtd_format = 0; + if (dusize) { + if (tpcb->tp_l_tpdusize > dusize) + tpcb->tp_l_tpdusize = dusize; + if (tpcb->tp_ptpdusize == 0 || + tpcb->tp_ptpdusize > param->p_ptpdusize) + tpcb->tp_ptpdusize = param->p_ptpdusize; + } else { + if (param->p_tpdusize != 0 && + tpcb->tp_tpdusize > param->p_tpdusize) + tpcb->tp_tpdusize = param->p_tpdusize; + tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; + } + } +done: + + IFTRACE(D_CONN) + tptrace(TPPTmisc, "tp_consist returns class xtdfmt cmd", + error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); + ENDTRACE + IFDEBUG(D_CONN) + printf( + "tp_consist rtns 0x%x class 0x%x xtd_fmt 0x%x cmd 0x%x\n", + error, tpcb->tp_class, tpcb->tp_xtd_format, cmd); + ENDDEBUG + return error; +} + +/* + * NAME: tp_ctloutput() + * + * CALLED FROM: + * [sg]etsockopt(), via so[sg]etopt(). + * + * FUNCTION and ARGUMENTS: + * Implements the socket options at transport level. + * (cmd) is either PRCO_SETOPT or PRCO_GETOPT (see ../sys/protosw.h). + * (so) is the socket. + * (level) is SOL_TRANSPORT (see ../sys/socket.h) + * (optname) is the particular command or option to be set. + * (**mp) is an mbuf structure. + * + * RETURN VALUE: + * ENOTSOCK if the socket hasn't got an associated tpcb + * EINVAL if + * trying to set window too big + * trying to set illegal max tpdu size + * trying to set illegal credit fraction + * trying to use unknown or unimplemented class of TP + * structure passed to set timer values is wrong size + * illegal combination of command/GET-SET option, + * e.g., GET w/ TPOPT_CDDATA_CLEAR: + * EOPNOTSUPP if the level isn't transport, or command is neither GET nor SET + * or if the transport-specific command is not implemented + * EISCONN if trying a command that isn't allowed after a connection + * is established + * ENOTCONN if trying a command that is allowed only if a connection is + * established + * EMSGSIZE if trying to give too much data on connect/disconnect + * + * SIDE EFFECTS: + * + * NOTES: + */ +ProtoHook +tp_ctloutput(cmd, so, level, optname, mp) + int cmd, level, optname; + struct socket *so; + struct mbuf **mp; +{ + struct tp_pcb *tpcb = sototpcb(so); + int s = splnet(); + caddr_t value; + unsigned val_len; + int error = 0; + + IFTRACE(D_REQUEST) + tptrace(TPPTmisc, "tp_ctloutput cmd so optname mp", + cmd, so, optname, mp); + ENDTRACE + IFDEBUG(D_REQUEST) + printf( + "tp_ctloutput so 0x%x cmd 0x%x optname 0x%x, mp 0x%x *mp 0x%x tpcb 0x%x\n", + so, cmd, optname, mp, mp?*mp:0, tpcb); + ENDDEBUG + if( tpcb == (struct tp_pcb *)0 ) { + error = ENOTSOCK; goto done; + } + if(*mp == MNULL) { + register struct mbuf *m; + + MGET(m, M_DONTWAIT, TPMT_SONAME); /* does off, type, next */ + if (m == NULL) { + splx(s); + return ENOBUFS; + } + m->m_len = 0; + m->m_act = 0; + *mp = m; + } + + /* + * Hook so one can set network options via a tp socket. + */ + if ( level == SOL_NETWORK ) { + if ((tpcb->tp_nlproto == NULL) || (tpcb->tp_npcb == NULL)) + error = ENOTSOCK; + else if (tpcb->tp_nlproto->nlp_ctloutput == NULL) + error = EOPNOTSUPP; + else + return ((tpcb->tp_nlproto->nlp_ctloutput)(cmd, optname, + tpcb->tp_npcb, *mp)); + goto done; + } else if ( level == SOL_SOCKET) { + if (optname == SO_RCVBUF && cmd == PRCO_SETOPT) { + u_long old_credit = tpcb->tp_maxlcredit; + tp_rsyset(tpcb); + if (tpcb->tp_rhiwat != so->so_rcv.sb_hiwat && + tpcb->tp_state == TP_OPEN && + (old_credit < tpcb->tp_maxlcredit)) + tp_emit(AK_TPDU_type, tpcb, + tpcb->tp_rcvnxt, 0, MNULL); + tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; + } + goto done; + } else if ( level != SOL_TRANSPORT ) { + error = EOPNOTSUPP; goto done; + } + if (cmd != PRCO_GETOPT && cmd != PRCO_SETOPT) { + error = EOPNOTSUPP; goto done; + } + if ( so->so_error ) { + error = so->so_error; goto done; + } + + /* The only options allowed after connection is established + * are GET (anything) and SET DISC DATA and SET PERF MEAS + */ + if ( ((so->so_state & SS_ISCONNECTING)||(so->so_state & SS_ISCONNECTED)) + && + (cmd == PRCO_SETOPT && + optname != TPOPT_DISC_DATA && + optname != TPOPT_CFRM_DATA && + optname != TPOPT_PERF_MEAS && + optname != TPOPT_CDDATA_CLEAR ) ) { + error = EISCONN; goto done; + } + /* The only options allowed after disconnection are GET DISC DATA, + * and TPOPT_PSTATISTICS + * and they're not allowed if the ref timer has gone off, because + * the tpcb is gone + */ + if ((so->so_state & (SS_ISCONNECTED | SS_ISCONFIRMING)) == 0) { + if ( so->so_pcb == (caddr_t)0 ) { + error = ENOTCONN; goto done; + } + if ( (tpcb->tp_state == TP_REFWAIT || tpcb->tp_state == TP_CLOSING) && + (optname != TPOPT_DISC_DATA && optname != TPOPT_PSTATISTICS)) { + error = ENOTCONN; goto done; + } + } + + value = mtod(*mp, caddr_t); /* it's aligned, don't worry, + * but lint complains about it + */ + val_len = (*mp)->m_len; + + switch (optname) { + + case TPOPT_INTERCEPT: +#define INA(t) (((struct inpcb *)(t->tp_npcb))->inp_laddr.s_addr) +#define ISOA(t) (((struct isopcb *)(t->tp_npcb))->isop_laddr->siso_addr) + + if ((so->so_state & SS_PRIV) == 0) { + error = EPERM; + } else if (cmd != PRCO_SETOPT || tpcb->tp_state != TP_CLOSED || + (tpcb->tp_flags & TPF_GENERAL_ADDR) || + tpcb->tp_next == 0) + error = EINVAL; + else { + register struct tp_pcb *t; + error = EADDRINUSE; + for (t = tp_listeners; t; t = t->tp_nextlisten) + if ((t->tp_flags & TPF_GENERAL_ADDR) == 0 && + t->tp_domain == tpcb->tp_domain) + switch (tpcb->tp_domain) { + default: + goto done; +#ifdef INET + case AF_INET: + if (INA(t) == INA(tpcb)) + goto done; + continue; +#endif +#ifdef ISO + case AF_ISO: + if (bcmp(ISOA(t).isoa_genaddr, ISOA(tpcb).isoa_genaddr, + ISOA(t).isoa_len) == 0) + goto done; + continue; +#endif + } + tpcb->tp_lsuffixlen = 0; + tpcb->tp_state = TP_LISTENING; + error = 0; + remque(tpcb); + tpcb->tp_next = tpcb->tp_prev = tpcb; + tpcb->tp_nextlisten = tp_listeners; + tp_listeners = tpcb; + } + break; + + case TPOPT_MY_TSEL: + if ( cmd == PRCO_GETOPT ) { + ASSERT( tpcb->tp_lsuffixlen <= MAX_TSAP_SEL_LEN ); + bcopy((caddr_t)tpcb->tp_lsuffix, value, tpcb->tp_lsuffixlen); + (*mp)->m_len = tpcb->tp_lsuffixlen; + } else /* cmd == PRCO_SETOPT */ { + if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { + printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); + error = EINVAL; + } else { + bcopy(value, (caddr_t)tpcb->tp_lsuffix, val_len); + tpcb->tp_lsuffixlen = val_len; + } + } + break; + + case TPOPT_PEER_TSEL: + if ( cmd == PRCO_GETOPT ) { + ASSERT( tpcb->tp_fsuffixlen <= MAX_TSAP_SEL_LEN ); + bcopy((caddr_t)tpcb->tp_fsuffix, value, tpcb->tp_fsuffixlen); + (*mp)->m_len = tpcb->tp_fsuffixlen; + } else /* cmd == PRCO_SETOPT */ { + if( (val_len > MAX_TSAP_SEL_LEN) || (val_len <= 0 )) { + printf("val_len 0x%x (*mp)->m_len 0x%x\n", val_len, (*mp)); + error = EINVAL; + } else { + bcopy(value, (caddr_t)tpcb->tp_fsuffix, val_len); + tpcb->tp_fsuffixlen = val_len; + } + } + break; + + case TPOPT_FLAGS: + IFDEBUG(D_REQUEST) + printf("%s TPOPT_FLAGS value 0x%x *value 0x%x, flags 0x%x \n", + cmd==PRCO_GETOPT?"GET":"SET", + value, + *value, + tpcb->tp_flags); + ENDDEBUG + + if ( cmd == PRCO_GETOPT ) { + *(int *)value = (int)tpcb->tp_flags; + (*mp)->m_len = sizeof(u_int); + } else /* cmd == PRCO_SETOPT */ { + error = EINVAL; goto done; + } + break; + + case TPOPT_PARAMS: + /* This handles: + * timer values, + * class, use of transport expedited data, + * max tpdu size, checksum, xtd format and + * disconnect indications, and may get rid of connect/disc data + */ + IFDEBUG(D_SETPARAMS) + printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, + cmd==PRCO_GETOPT?"GET":"SET"); + ENDDEBUG + IFDEBUG(D_REQUEST) + printf("TPOPT_PARAMS value 0x%x, cmd %s \n", value, + cmd==PRCO_GETOPT?"GET":"SET"); + ENDDEBUG + + if ( cmd == PRCO_GETOPT ) { + *(struct tp_conn_param *)value = tpcb->_tp_param; + (*mp)->m_len = sizeof(tpcb->_tp_param); + } else /* cmd == PRCO_SETOPT */ { + if( (error = + tp_consistency(tpcb, TP_STRICT | TP_FORCE, + (struct tp_conn_param *)value))==0) { + /* + * tp_consistency doesn't copy the whole set of params + */ + tpcb->_tp_param = *(struct tp_conn_param *)value; + (*mp)->m_len = sizeof(tpcb->_tp_param); + } + } + break; + + case TPOPT_PSTATISTICS: +#ifdef TP_PERF_MEAS + if (cmd == PRCO_SETOPT) { + error = EINVAL; goto done; + } + IFPERF(tpcb) + if (*mp) { + struct mbuf * n; + do { + MFREE(*mp, n); + *mp = n; + } while (n); + } + *mp = m_copym(tpcb->tp_p_mbuf, (int)M_COPYALL, M_WAITOK); + ENDPERF + else { + error = EINVAL; goto done; + } + break; +#else + error = EOPNOTSUPP; + goto done; +#endif /* TP_PERF_MEAS */ + + case TPOPT_CDDATA_CLEAR: + if (cmd == PRCO_GETOPT) { + error = EINVAL; + } else { + if (tpcb->tp_ucddata) { + m_freem(tpcb->tp_ucddata); + tpcb->tp_ucddata = 0; + } + } + break; + + case TPOPT_CFRM_DATA: + case TPOPT_DISC_DATA: + case TPOPT_CONN_DATA: + if( tpcb->tp_class == TP_CLASS_0 ) { + error = EOPNOTSUPP; + break; + } + IFDEBUG(D_REQUEST) + printf("%s\n", optname==TPOPT_DISC_DATA?"DISC data":"CONN data"); + printf("m_len 0x%x, vallen 0x%x so_snd.cc 0x%x\n", + (*mp)->m_len, val_len, so->so_snd.sb_cc); + dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput: sosnd "); + ENDDEBUG + if (cmd == PRCO_SETOPT) { + int len = tpcb->tp_ucddata ? tpcb->tp_ucddata->m_len : 0; + /* can append connect data in several calls */ + if (len + val_len > + (optname==TPOPT_CONN_DATA?TP_MAX_CR_DATA:TP_MAX_DR_DATA) ) { + error = EMSGSIZE; goto done; + } + (*mp)->m_next = MNULL; + (*mp)->m_act = 0; + if (tpcb->tp_ucddata) + m_cat(tpcb->tp_ucddata, *mp); + else + tpcb->tp_ucddata = *mp; + IFDEBUG(D_REQUEST) + dump_mbuf(tpcb->tp_ucddata, "tp_ctloutput after CONN_DATA"); + ENDDEBUG + IFTRACE(D_REQUEST) + tptrace(TPPTmisc,"C/D DATA: flags snd.sbcc val_len", + tpcb->tp_flags, so->so_snd.sb_cc,val_len,0); + ENDTRACE + *mp = MNULL; + if (optname == TPOPT_CFRM_DATA && (so->so_state & SS_ISCONFIRMING)) + (void) tp_confirm(tpcb); + } + break; + + case TPOPT_PERF_MEAS: +#ifdef TP_PERF_MEAS + if (cmd == PRCO_GETOPT) { + *value = (u_int)tpcb->tp_perf_on; + (*mp)->m_len = sizeof(u_int); + } else if (cmd == PRCO_SETOPT) { + (*mp)->m_len = 0; + if ((*value) != 0 && (*value) != 1 ) + error = EINVAL; + else tpcb->tp_perf_on = (*value); + } + if( tpcb->tp_perf_on ) + error = tp_setup_perf(tpcb); +#else /* TP_PERF_MEAS */ + error = EOPNOTSUPP; +#endif /* TP_PERF_MEAS */ + break; + + default: + error = EOPNOTSUPP; + } + +done: + IFDEBUG(D_REQUEST) + dump_mbuf(so->so_snd.sb_mb, "tp_ctloutput sosnd at end"); + dump_mbuf(*mp, "tp_ctloutput *mp"); + ENDDEBUG + /* + * sigh: getsockopt looks only at m_len : all output data must + * reside in the first mbuf + */ + if (*mp) { + if (cmd == PRCO_SETOPT) { + m_freem(*mp); + *mp = MNULL; + } else { + ASSERT ( m_compress(*mp, mp) <= MLEN ); + if (error) + (*mp)->m_len = 0; + IFDEBUG(D_REQUEST) + dump_mbuf(*mp, "tp_ctloutput *mp after compress"); + ENDDEBUG + } + } + splx(s); + return error; +} diff --git a/sys/netiso/tp_param.h b/sys/netiso/tp_param.h new file mode 100644 index 0000000..f1862a2 --- /dev/null +++ b/sys/netiso/tp_param.h @@ -0,0 +1,367 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_param.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_param.h,v 5.3 88/11/18 17:28:18 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_param.h,v $ + * + */ + +#ifndef __TP_PARAM__ +#define __TP_PARAM__ + + +/****************************************************** + * compile time parameters that can be changed + *****************************************************/ + +#define TP_CLASSES_IMPLEMENTED 0x11 /* zero and 4 */ + +#define TP_DECBIT_CLEAR_COUNT 3 + +/*#define N_TPREF 100 */ +#ifdef KERNEL +extern int N_TPREF; +#endif + +#define TP_SOCKBUFSIZE ((u_long)4096) +#define TP0_SOCKBUFSIZE ((u_long)512) +#define MAX_TSAP_SEL_LEN 64 + +/* maximum tpdu size we'll accept: */ +#define TP_TPDUSIZE 0xc /* 4096 octets for classes 1-4*/ +#define TP0_TPDUSIZE 0xb /* 2048 octets for class 0 */ +#define TP_DFL_TPDUSIZE 0x7 /* 128 octets default */ + /* NOTE: don't ever negotiate 8192 because could get + * wraparound in checksumming + * (No mtu is likely to be larger than 4K anyway...) + */ +#define TP_NRETRANS 12 /* TCP_MAXRXTSHIFT + 1 */ +#define TP_MAXRXTSHIFT 6 /* factor of 64 */ +#define TP_MAXPORT 0xefff + +/* ALPHA: to be used in the context: gain= 1/(2**alpha), or + * put another way, gaintimes(x) (x)>>alpha (forgetting the case alpha==0) + */ +#define TP_RTT_ALPHA 3 +#define TP_RTV_ALPHA 2 +#define TP_REXMTVAL(tpcb)\ + ((tp_rttadd + (tpcb)->tp_rtt + ((tpcb)->tp_rtv) << 2) / tp_rttdiv) +#define TP_RANGESET(tv, value, min, max) \ + ((tv = value) > (max) ? (tv = max) : (tv < min ? tv = min : tv)) + +/* + * not sure how to treat data on disconnect + */ +#define T_CONN_DATA 0x1 +#define T_DISCONNECT 0x2 +#define T_DISC_DATA 0x4 +#define T_XDATA 0x8 + +#define ISO_CLNS 0 +#define IN_CLNS 1 +#define ISO_CONS 2 +#define ISO_COSNS 3 +#define TP_MAX_NETSERVICES 3 + +/* Indices into tp stats ackreason[i] */ +#define _ACK_DONT_ 0 +#define _ACK_STRAT_EACH_ 0x1 +#define _ACK_STRAT_FULLWIN_ 0x2 +#define _ACK_DUP_ 0x3 +#define _ACK_EOT_ 0x4 +#define _ACK_REORDER_ 0x5 +#define _ACK_USRRCV_ 0x6 +#define _ACK_FCC_ 0x7 +#define _ACK_NUM_REASONS_ 0x8 + +/* masks for use in tp_stash() */ +#define ACK_DONT 0 +#define ACK_STRAT_EACH (1<< _ACK_STRAT_EACH_) +#define ACK_STRAT_FULLWIN (1<< _ACK_STRAT_FULLWIN_) +#define ACK_DUP (1<< _ACK_DUP_) +#define ACK_EOT (1<< _ACK_EOT_) +#define ACK_REORDER (1<< _ACK_REORDER_) + +/****************************************************** + * constants used in the protocol + *****************************************************/ + +#define TP_VERSION 0x1 + +#define TP_MAX_HEADER_LEN 256 + +#define TP_MIN_TPDUSIZE 0x7 /* 128 octets */ +#define TP_MAX_TPDUSIZE 0xd /* 8192 octets */ + +#define TP_MAX_XPD_DATA 0x10 /* 16 octets */ +#define TP_MAX_CC_DATA 0x20 /* 32 octets */ +#define TP_MAX_CR_DATA TP_MAX_CC_DATA +#define TP_MAX_DR_DATA 0x40 /* 64 octets */ + +#define TP_XTD_FMT_BIT 0x80000000 +#define TP_XTD_FMT_MASK 0x7fffffff +#define TP_NML_FMT_BIT 0x80 +#define TP_NML_FMT_MASK 0x7f + +/* + * values for the tpdu_type field, 2nd byte in a tpdu + */ + +#define TP_MIN_TPDUTYPE 0x1 + +#define XPD_TPDU_type 0x1 +#define XAK_TPDU_type 0x2 +#define GR_TPDU_type 0x3 +#define AK_TPDU_type 0x6 +#define ER_TPDU_type 0x7 +#define DR_TPDU_type 0x8 +#define DC_TPDU_type 0xc +#define CC_TPDU_type 0xd +#define CR_TPDU_type 0xe +#define DT_TPDU_type 0xf + +#define TP_MAX_TPDUTYPE 0xf + +/* + * identifiers for the variable-length options in tpdus + */ + +#define TPP_acktime 0x85 +#define TPP_residER 0x86 +#define TPP_priority 0x87 +#define TPP_transdelay 0x88 +#define TPP_throughput 0x89 +#define TPP_subseq 0x8a +#define TPP_flow_cntl_conf 0x8c /* not implemented */ +#define TPP_addl_info 0xe0 +#define TPP_tpdu_size 0xc0 +#define TPP_calling_sufx 0xc1 +#define TPP_invalid_tpdu 0xc1 /* the bozos used a value twice */ +#define TPP_called_sufx 0xc2 +#define TPP_checksum 0xc3 +#define TPP_vers 0xc4 +#define TPP_security 0xc5 +#define TPP_addl_opt 0xc6 +#define TPP_alt_class 0xc7 +#define TPP_perf_meas 0xc8 /* local item : perf meas on, svp */ +#define TPP_ptpdu_size 0xf0 /* preferred TPDU size */ +#define TPP_inact_time 0xf2 /* inactivity time exchanged */ + + +/****************************************************** + * Some fundamental data types + *****************************************************/ +#ifndef TRUE +#define TRUE 1 +#endif /* TRUE */ + +#ifndef FALSE +#define FALSE 0 +#endif /* FALSE */ + +#define TP_LOCAL 22 +#define TP_FOREIGN 33 + +#ifndef EOK +#define EOK 0 +#endif /* EOK */ + +#define TP_CLASS_0 (1<<0) +#define TP_CLASS_1 (1<<1) +#define TP_CLASS_2 (1<<2) +#define TP_CLASS_3 (1<<3) +#define TP_CLASS_4 (1<<4) + +#define TP_FORCE 0x1 +#define TP_STRICT 0x2 + +#ifndef MNULL +#define MNULL (struct mbuf *)0 +#endif /* MNULL */ + /* if ../sys/mbuf.h gets MT_types up to 0x40, these will + * have to be changed: + */ +#define MT_XPD 0x44 +#define MT_EOT 0x40 + +#define TP_ENOREF 0x80000000 + +typedef unsigned int SeqNum; +typedef unsigned short RefNum; +typedef int ProtoHook; + +/****************************************************** + * Macro used all over, for driver + *****************************************************/ + +#define DoEvent(x) \ + ((E.ev_number=(x)),(tp_driver(tpcb,&E))) + +/****************************************************** + * Some macros used all over, for timestamping + *****************************************************/ + +#define GET_CUR_TIME(tvalp) ((*tvalp) = time) + +#define GET_TIME_SINCE(oldtvalp, diffp) {\ + (diffp)->tv_sec = time.tv_sec - (oldtvalp)->tv_sec;\ + (diffp)->tv_usec = time.tv_usec - (oldtvalp)->tv_usec;\ + if( (diffp)->tv_usec <0 ) {\ + (diffp)->tv_sec --;\ + (diffp)->tv_usec = 1000000 - (diffp)->tv_usec;\ + }\ +} + +/****************************************************** + * Some macros used for address families + *****************************************************/ + +#define satosiso(ADDR) ((struct sockaddr_iso *)(ADDR)) +#define satosin(ADDR) ((struct sockaddr_in *)(ADDR)) + +/****************************************************** + * Macro used for changing types of mbufs + *****************************************************/ + +#define CHANGE_MTYPE(m, TYPE)\ + if((m)->m_type != TYPE) { \ + mbstat.m_mtypes[(m)->m_type]--; mbstat.m_mtypes[TYPE]++; \ + (m)->m_type = TYPE; \ + } + +/****************************************************** + * Macros used for adding options to a tpdu header and for + * parsing the headers. + * Options are variable-length and must be bcopy-d because on the + * RT your assignments must be N-word aligned for objects of length + * N. Such a drag. + *****************************************************/ + +struct tp_vbp { + u_char tpv_code; + char tpv_len; + char tpv_val; +}; +#define vbptr(x) ((struct tp_vbp *)(x)) +#define vbval(x,type) (*((type *)&(((struct tp_vbp *)(x))->tpv_val))) +#define vbcode(x) (vbptr(x)->tpv_code) +#define vblen(x) (vbptr(x)->tpv_len) + +#define vb_putval(dst,type,src)\ + bcopy((caddr_t)&(src),(caddr_t)&(((struct tp_vbp *)(dst))->tpv_val),\ + sizeof(type)) + +#define vb_getval(src,type,dst)\ +bcopy((caddr_t)&(((struct tp_vbp *)(src))->tpv_val),(caddr_t)&(dst),sizeof(type)) + +#define ADDOPTION(type, DU, len, src)\ +{ register caddr_t P;\ + P = (caddr_t)(DU) + (int)((DU)->tpdu_li);\ + vbptr(P)->tpv_code = type;\ + vbptr(P)->tpv_len = len;\ + bcopy((caddr_t)&src, (caddr_t)&(vbptr(P)->tpv_val), (unsigned)len);\ + DU->tpdu_li += len+2;/* 1 for code, 1 for length */\ +} +/****************************************************** + * Macro for the local credit: + * uses max transmission unit for the ll + * (as modified by the max TPDU size negotiated) + *****************************************************/ + +#if defined(ARGO_DEBUG)&&!defined(LOCAL_CREDIT_EXPAND) +#define LOCAL_CREDIT(tpcb) tp_local_credit(tpcb) +#else +#define LOCAL_CREDIT(tpcb) { if (tpcb->tp_rsycnt == 0) {\ + register struct sockbuf *xxsb = &((tpcb)->tp_sock->so_rcv);\ + register int xxi = sbspace(xxsb);\ + xxi = (xxi<0) ? 0 : ((xxi) / (tpcb)->tp_l_tpdusize);\ + xxi = min(xxi, (tpcb)->tp_maxlcredit); \ + if (!(tpcb->tp_cebit_off)) { \ + (tpcb)->tp_lcredit = ROUND((tpcb)->tp_win_recv); \ + if (xxi < (tpcb)->tp_lcredit) { \ + (tpcb)->tp_lcredit = xxi; \ + } \ + } else \ + (tpcb)->tp_lcredit = xxi; \ +} } +#endif /* ARGO_DEBUG */ + +#ifdef KERNEL +extern int tp_rttadd, tp_rttdiv; +#include <sys/syslog.h> +#define printf logpri(LOG_DEBUG),addlog + +#ifndef tp_NSTATES + +#include <netiso/tp_states.h> +#include <netiso/tp_events.h> +#if defined(__STDC__) || defined(__cplusplus) +#undef ATTR +#define ATTR(X) ev_union.EV_ ## X +#endif /* defined(__STDC__) || defined(__cplusplus) */ + +#endif /* tp_NSTATES */ +#endif /* KERNEL */ + +#endif /* __TP_PARAM__ */ diff --git a/sys/netiso/tp_pcb.c b/sys/netiso/tp_pcb.c new file mode 100644 index 0000000..de345c1 --- /dev/null +++ b/sys/netiso/tp_pcb.c @@ -0,0 +1,999 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_pcb.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_pcb.c,v 5.4 88/11/18 17:28:24 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.c,v $ + * + * + * This is the initialization and cleanup stuff - + * for the tp machine in general as well as for the individual pcbs. + * tp_init() is called at system startup. tp_attach() and tp_getref() are + * called when a socket is created. tp_detach() and tp_freeref() + * are called during the closing stage and/or when the reference timer + * goes off. + * tp_soisdisconnecting() and tp_soisdisconnected() are tp-specific + * versions of soisconnect* + * and are called (obviously) during the closing phase. + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <netiso/argo_debug.h> +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_ip.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_meas.h> +#include <netiso/tp_seq.h> +#include <netiso/tp_clnp.h> + +/* ticks are in units of: + * 500 nano-fortnights ;-) or + * 500 ms or + * 1/2 second + */ + +struct tp_conn_param tp_conn_param[] = { + /* ISO_CLNS: TP4 CONNECTION LESS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 20, /* 10 sec */ /* short p_dr_ticks; */ + + 20, /* 10 sec */ /* short p_cc_ticks; */ + 20, /* 10 sec */ /* short p_dt_ticks; */ + + 40, /* 20 sec */ /* short p_x_ticks; */ + 80, /* 40 sec */ /* short p_cr_ticks;*/ + + 240, /* 2 min */ /* short p_keepalive_ticks;*/ + 10, /* 5 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 360, /* 3 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP_SOCKBUFSIZE, /* short p_winsize */ + TP_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW | TPRX_FASTSTART, + /* 4 bits p_rx_strat*/ + TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ + 1, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 1, /* no disc indications */ + 0, /* don't change params */ + ISO_CLNS, /* p_netservice */ + }, + /* IN_CLNS: TP4 CONNECTION LESS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 20, /* 10 sec */ /* short p_dr_ticks; */ + + 20, /* 10 sec */ /* short p_cc_ticks; */ + 20, /* 10 sec */ /* short p_dt_ticks; */ + + 40, /* 20 sec */ /* short p_x_ticks; */ + 80, /* 40 sec */ /* short p_cr_ticks;*/ + + 240, /* 2 min */ /* short p_keepalive_ticks;*/ + 10, /* 5 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 360, /* 3 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP_SOCKBUFSIZE, /* short p_winsize */ + TP_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW | TPRX_FASTSTART, + /* 4 bits p_rx_strat*/ + TP_CLASS_4, /* 5 bits p_class */ + 1, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 1, /* no disc indications */ + 0, /* don't change params */ + IN_CLNS, /* p_netservice */ + }, + /* ISO_CONS: TP0 CONNECTION MODE */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 0, /* n/a */ /* short p_dr_ticks; */ + + 40, /* 20 sec */ /* short p_cc_ticks; */ + 0, /* n/a */ /* short p_dt_ticks; */ + + 0, /* n/a */ /* short p_x_ticks; */ + 360, /* 3 min */ /* short p_cr_ticks;*/ + + 0, /* n/a */ /* short p_keepalive_ticks;*/ + 0, /* n/a */ /* short p_sendack_ticks; */ + + 600, /* for cr/cc to clear *//* short p_ref_ticks; */ + 0, /* n/a */ /* short p_inact_ticks; */ + + /* Use tp4 defaults just in case the user changes ONLY + * the class + */ + (short) 100, /* short p_lcdtfract */ + (short) TP0_SOCKBUFSIZE, /* short p_winsize */ + TP0_TPDUSIZE, /* 8 bits p_tpdusize */ + + 0, /* 4 bits p_ack_strat */ + 0, /* 4 bits p_rx_strat*/ + TP_CLASS_0, /* 5 bits p_class */ + 0, /* 1 bit xtd format */ + 0, /* 1 bit xpd service */ + 0, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + ISO_CONS, /* p_netservice */ + }, + /* ISO_COSNS: TP4 CONNECTION LESS SERVICE over CONSNS */ + { + TP_NRETRANS, /* short p_Nretrans; */ + 40, /* 20 sec */ /* short p_dr_ticks; */ + + 40, /* 20 sec */ /* short p_cc_ticks; */ + 80, /* 40 sec */ /* short p_dt_ticks; */ + + 120, /* 1 min */ /* short p_x_ticks; */ + 360, /* 3 min */ /* short p_cr_ticks;*/ + + 360, /* 3 min */ /* short p_keepalive_ticks;*/ + 20, /* 10 sec */ /* short p_sendack_ticks; */ + + 600, /* 5 min */ /* short p_ref_ticks; */ + 480, /* 4 min */ /* short p_inact_ticks; */ + + (short) 100, /* short p_lcdtfract */ + (short) TP0_SOCKBUFSIZE, /* short p_winsize */ + TP0_TPDUSIZE, /* u_char p_tpdusize */ + + TPACK_WINDOW, /* 4 bits p_ack_strat */ + TPRX_USE_CW , /* No fast start */ + /* 4 bits p_rx_strat*/ + TP_CLASS_4 | TP_CLASS_0,/* 5 bits p_class */ + 0, /* 1 bit xtd format */ + 1, /* 1 bit xpd service */ + 1, /* 1 bit use_checksum */ + 0, /* 1 bit use net xpd */ + 0, /* 1 bit use rcc */ + 0, /* 1 bit use efc */ + 0, /* no disc indications */ + 0, /* don't change params */ + ISO_COSNS, /* p_netservice */ + }, +}; + +#ifdef INET +int in_putnetaddr(); +int in_getnetaddr(); +int in_cmpnetaddr(); +int in_putsufx(); +int in_getsufx(); +int in_recycle_tsuffix(); +int tpip_mtu(); +int in_pcbbind(); +int in_pcbconnect(); +int in_pcbdisconnect(); +int in_pcbdetach(); +int in_pcballoc(); +int tpip_output(); +int tpip_output_dg(); +struct inpcb tp_inpcb; +#endif /* INET */ +#ifdef ISO +int iso_putnetaddr(); +int iso_getnetaddr(); +int iso_cmpnetaddr(); +int iso_putsufx(); +int iso_getsufx(); +int iso_recycle_tsuffix(); +int tpclnp_mtu(); +int iso_pcbbind(); +int iso_pcbconnect(); +int iso_pcbdisconnect(); +int iso_pcbdetach(); +int iso_pcballoc(); +int tpclnp_output(); +int tpclnp_output_dg(); +int iso_nlctloutput(); +struct isopcb tp_isopcb; +#endif /* ISO */ +#ifdef TPCONS +int iso_putnetaddr(); +int iso_getnetaddr(); +int iso_cmpnetaddr(); +int iso_putsufx(); +int iso_getsufx(); +int iso_recycle_tsuffix(); +int iso_pcbbind(); +int tpcons_pcbconnect(); +int tpclnp_mtu(); +int iso_pcbdisconnect(); +int iso_pcbdetach(); +int iso_pcballoc(); +int tpcons_output(); +struct isopcb tp_isopcb; +#endif /* TPCONS */ + + +struct nl_protosw nl_protosw[] = { + /* ISO_CLNS */ +#ifdef ISO + { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, + iso_putsufx, iso_getsufx, + iso_recycle_tsuffix, + tpclnp_mtu, iso_pcbbind, iso_pcbconnect, + iso_pcbdisconnect, iso_pcbdetach, + iso_pcballoc, + tpclnp_output, tpclnp_output_dg, iso_nlctloutput, + (caddr_t) &tp_isopcb, + }, +#else + { 0 }, +#endif /* ISO */ + /* IN_CLNS */ +#ifdef INET + { AF_INET, in_putnetaddr, in_getnetaddr, in_cmpnetaddr, + in_putsufx, in_getsufx, + in_recycle_tsuffix, + tpip_mtu, in_pcbbind, in_pcbconnect, + in_pcbdisconnect, in_pcbdetach, + in_pcballoc, + tpip_output, tpip_output_dg, /* nl_ctloutput */ NULL, + (caddr_t) &tp_inpcb, + }, +#else + { 0 }, +#endif /* INET */ + /* ISO_CONS */ +#if defined(ISO) && defined(TPCONS) + { AF_ISO, iso_putnetaddr, iso_getnetaddr, iso_cmpnetaddr, + iso_putsufx, iso_getsufx, + iso_recycle_tsuffix, + tpclnp_mtu, iso_pcbbind, tpcons_pcbconnect, + iso_pcbdisconnect, iso_pcbdetach, + iso_pcballoc, + tpcons_output, tpcons_output, iso_nlctloutput, + (caddr_t) &tp_isopcb, + }, +#else + { 0 }, +#endif /* ISO_CONS */ + /* End of protosw marker */ + { 0 } +}; + +u_long tp_sendspace = 1024 * 4; +u_long tp_recvspace = 1024 * 4; + +/* + * NAME: tp_init() + * + * CALLED FROM: + * autoconf through the protosw structure + * + * FUNCTION: + * initialize tp machine + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +int +tp_init() +{ + static int init_done=0; + void tp_timerinit(); + + if (init_done++) + return 0; + + + /* FOR INET */ + tp_inpcb.inp_next = tp_inpcb.inp_prev = &tp_inpcb; + /* FOR ISO */ + tp_isopcb.isop_next = tp_isopcb.isop_prev = &tp_isopcb; + + tp_start_win = 2; + + tp_timerinit(); + bzero((caddr_t)&tp_stat, sizeof(struct tp_stat)); + return 0; +} + +/* + * NAME: tp_soisdisconnecting() + * + * CALLED FROM: + * tp.trans + * + * FUNCTION and ARGUMENTS: + * Set state of the socket (so) to reflect that fact that we're disconnectING + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * This differs from the regular soisdisconnecting() in that the latter + * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. + * We don't want to set those flags because those flags will cause + * a SIGPIPE to be delivered in sosend() and we don't like that. + * If anyone else is sleeping on this socket, wake 'em up. + */ +void +tp_soisdisconnecting(so) + register struct socket *so; +{ + soisdisconnecting(so); + so->so_state &= ~SS_CANTSENDMORE; + IFPERF(sototpcb(so)) + register struct tp_pcb *tpcb = sototpcb(so); + u_int fsufx, lsufx; + + bcopy ((caddr_t)tpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); + bcopy ((caddr_t)tpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); + + tpmeas(tpcb->tp_lref, TPtime_close, &time, fsufx, lsufx, tpcb->tp_fref); + tpcb->tp_perf_on = 0; /* turn perf off */ + ENDPERF +} + + +/* + * NAME: tp_soisdisconnected() + * + * CALLED FROM: + * tp.trans + * + * FUNCTION and ARGUMENTS: + * Set state of the socket (so) to reflect that fact that we're disconnectED + * Set the state of the reference structure to closed, and + * recycle the suffix. + * Start a reference timer. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * This differs from the regular soisdisconnected() in that the latter + * also sets the SS_CANTRECVMORE and SS_CANTSENDMORE flags. + * We don't want to set those flags because those flags will cause + * a SIGPIPE to be delivered in sosend() and we don't like that. + * If anyone else is sleeping on this socket, wake 'em up. + */ +void +tp_soisdisconnected(tpcb) + register struct tp_pcb *tpcb; +{ + register struct socket *so = tpcb->tp_sock; + + soisdisconnecting(so); + so->so_state &= ~SS_CANTSENDMORE; + IFPERF(tpcb) + register struct tp_pcb *ttpcb = sototpcb(so); + u_int fsufx, lsufx; + + /* CHOKE */ + bcopy ((caddr_t)ttpcb->tp_fsuffix, (caddr_t)&fsufx, sizeof(u_int) ); + bcopy ((caddr_t)ttpcb->tp_lsuffix, (caddr_t)&lsufx, sizeof(u_int) ); + + tpmeas(ttpcb->tp_lref, TPtime_close, + &time, &lsufx, &fsufx, ttpcb->tp_fref); + tpcb->tp_perf_on = 0; /* turn perf off */ + ENDPERF + + tpcb->tp_refstate = REF_FROZEN; + tp_recycle_tsuffix(tpcb); + tp_etimeout(tpcb, TM_reference, (int)tpcb->tp_refer_ticks); +} + +/* + * NAME: tp_freeref() + * + * CALLED FROM: + * tp.trans when the reference timer goes off, and + * from tp_attach() and tp_detach() when a tpcb is partially set up but not + * set up enough to have a ref timer set for it, and it's discarded + * due to some sort of error or an early close() + * + * FUNCTION and ARGUMENTS: + * Frees the reference represented by (r) for re-use. + * + * RETURNS: Nothing + * + * SIDE EFFECTS: + * + * NOTES: better be called at clock priority !!!!! + */ +void +tp_freeref(n) +RefNum n; +{ + register struct tp_ref *r = tp_ref + n; + register struct tp_pcb *tpcb; + + tpcb = r->tpr_pcb; + IFDEBUG(D_TIMER) + printf("tp_freeref called for ref %d pcb %x maxrefopen %d\n", + n, tpcb, tp_refinfo.tpr_maxopen); + ENDDEBUG + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_freeref ref maxrefopen pcb", + n, tp_refinfo.tpr_maxopen, tpcb, 0); + ENDTRACE + if (tpcb == 0) + return; + IFDEBUG(D_CONN) + printf("tp_freeref: CLEARING tpr_pcb 0x%x\n", tpcb); + ENDDEBUG + r->tpr_pcb = (struct tp_pcb *)0; + tpcb->tp_refstate = REF_FREE; + + for (r = tp_ref + tp_refinfo.tpr_maxopen; r > tp_ref; r--) + if (r->tpr_pcb) + break; + tp_refinfo.tpr_maxopen = r - tp_ref; + tp_refinfo.tpr_numopen--; + + IFDEBUG(D_TIMER) + printf("tp_freeref ends w/ maxrefopen %d\n", tp_refinfo.tpr_maxopen); + ENDDEBUG +} + +/* + * NAME: tp_getref() + * + * CALLED FROM: + * tp_attach() + * + * FUNCTION and ARGUMENTS: + * obtains the next free reference and allocates the appropriate + * ref structure, links that structure to (tpcb) + * + * RETURN VALUE: + * a reference number + * or TP_ENOREF + * + * SIDE EFFECTS: + * + * NOTES: + */ +u_long +tp_getref(tpcb) + register struct tp_pcb *tpcb; +{ + register struct tp_ref *r, *rlim; + register int i; + caddr_t obase; + unsigned size; + + if (++tp_refinfo.tpr_numopen < tp_refinfo.tpr_size) + for (r = tp_refinfo.tpr_base, rlim = r + tp_refinfo.tpr_size; + ++r < rlim; ) /* tp_ref[0] is never used */ + if (r->tpr_pcb == 0) + goto got_one; + /* else have to allocate more space */ + + obase = (caddr_t)tp_refinfo.tpr_base; + size = tp_refinfo.tpr_size * sizeof(struct tp_ref); + r = (struct tp_ref *) malloc(size + size, M_PCB, M_NOWAIT); + if (r == 0) + return (--tp_refinfo.tpr_numopen, TP_ENOREF); + tp_refinfo.tpr_base = tp_ref = r; + tp_refinfo.tpr_size *= 2; + bcopy(obase, (caddr_t)r, size); + free(obase, M_PCB); + r = (struct tp_ref *)(size + (caddr_t)r); + bzero((caddr_t)r, size); + +got_one: + r->tpr_pcb = tpcb; + tpcb->tp_refstate = REF_OPENING; + i = r - tp_refinfo.tpr_base; + if (tp_refinfo.tpr_maxopen < i) + tp_refinfo.tpr_maxopen = i; + return (u_long)i; +} + +/* + * NAME: tp_set_npcb() + * + * CALLED FROM: + * tp_attach(), tp_route_to() + * + * FUNCTION and ARGUMENTS: + * given a tpcb, allocate an appropriate lower-lever npcb, freeing + * any old ones that might need re-assigning. + */ +tp_set_npcb(tpcb) +register struct tp_pcb *tpcb; +{ + register struct socket *so = tpcb->tp_sock; + int error; + + if (tpcb->tp_nlproto && tpcb->tp_npcb) { + short so_state = so->so_state; + so->so_state &= ~SS_NOFDREF; + tpcb->tp_nlproto->nlp_pcbdetach(tpcb->tp_npcb); + so->so_state = so_state; + } + tpcb->tp_nlproto = &nl_protosw[tpcb->tp_netservice]; + /* xx_pcballoc sets so_pcb */ + error = tpcb->tp_nlproto->nlp_pcballoc(so, tpcb->tp_nlproto->nlp_pcblist); + tpcb->tp_npcb = so->so_pcb; + so->so_pcb = (caddr_t)tpcb; + return (error); +} +/* + * NAME: tp_attach() + * + * CALLED FROM: + * tp_usrreq, PRU_ATTACH + * + * FUNCTION and ARGUMENTS: + * given a socket (so) and a protocol family (dom), allocate a tpcb + * and ref structure, initialize everything in the structures that + * needs to be initialized. + * + * RETURN VALUE: + * 0 ok + * EINVAL if DEBUG(X) in is on and a disaster has occurred + * ENOPROTOOPT if TP hasn't been configured or if the + * socket wasn't created with tp as its protocol + * EISCONN if this socket is already part of a connection + * ETOOMANYREFS if ran out of tp reference numbers. + * E* whatever error is returned from soreserve() + * for from the network-layer pcb allocation routine + * + * SIDE EFFECTS: + * + * NOTES: + */ +tp_attach(so, protocol) + struct socket *so; + int protocol; +{ + register struct tp_pcb *tpcb; + int error = 0; + int dom = so->so_proto->pr_domain->dom_family; + u_long lref; + extern struct tp_conn_param tp_conn_param[]; + + IFDEBUG(D_CONN) + printf("tp_attach:dom 0x%x so 0x%x ", dom, so); + ENDDEBUG + IFTRACE(D_CONN) + tptrace(TPPTmisc, "tp_attach:dom so", dom, so, 0, 0); + ENDTRACE + + if (so->so_pcb != NULL) { + return EISCONN; /* socket already part of a connection*/ + } + + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) + error = soreserve(so, tp_sendspace, tp_recvspace); + /* later an ioctl will allow reallocation IF still in closed state */ + + if (error) + goto bad2; + + MALLOC(tpcb, struct tp_pcb *, sizeof(*tpcb), M_PCB, M_NOWAIT); + if (tpcb == NULL) { + error = ENOBUFS; + goto bad2; + } + bzero( (caddr_t)tpcb, sizeof (struct tp_pcb) ); + + if ( ((lref = tp_getref(tpcb)) & TP_ENOREF) != 0 ) { + error = ETOOMANYREFS; + goto bad3; + } + tpcb->tp_lref = lref; + tpcb->tp_sock = so; + tpcb->tp_domain = dom; + tpcb->tp_rhiwat = so->so_rcv.sb_hiwat; + /* tpcb->tp_proto = protocol; someday maybe? */ + if (protocol && protocol<ISOPROTO_TP4) { + tpcb->tp_netservice = ISO_CONS; + tpcb->tp_snduna = (SeqNum) -1;/* kludge so the pseudo-ack from the CR/CC + * will generate correct fake-ack values + */ + } else { + tpcb->tp_netservice = (dom== AF_INET)?IN_CLNS:ISO_CLNS; + /* the default */ + } + tpcb->_tp_param = tp_conn_param[tpcb->tp_netservice]; + + tpcb->tp_state = TP_CLOSED; + tpcb->tp_vers = TP_VERSION; + tpcb->tp_notdetached = 1; + + /* Spec says default is 128 octets, + * that is, if the tpdusize argument never appears, use 128. + * As the initiator, we will always "propose" the 2048 + * size, that is, we will put this argument in the CR + * always, but accept what the other side sends on the CC. + * If the initiator sends us something larger on a CR, + * we'll respond w/ this. + * Our maximum is 4096. See tp_chksum.c comments. + */ + tpcb->tp_cong_win = + tpcb->tp_l_tpdusize = 1 << tpcb->tp_tpdusize; + + tpcb->tp_seqmask = TP_NML_FMT_MASK; + tpcb->tp_seqbit = TP_NML_FMT_BIT; + tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; + + /* attach to a network-layer protoswitch */ + if ( error = tp_set_npcb(tpcb)) + goto bad4; + ASSERT( tpcb->tp_nlproto->nlp_afamily == tpcb->tp_domain); + + /* nothing to do for iso case */ + if( dom == AF_INET ) + sotoinpcb(so)->inp_ppcb = (caddr_t) tpcb; + + return 0; + +bad4: + IFDEBUG(D_CONN) + printf("BAD4 in tp_attach, so 0x%x\n", so); + ENDDEBUG + tp_freeref(tpcb->tp_lref); + +bad3: + IFDEBUG(D_CONN) + printf("BAD3 in tp_attach, so 0x%x\n", so); + ENDDEBUG + + free((caddr_t)tpcb, M_PCB); /* never a cluster */ + +bad2: + IFDEBUG(D_CONN) + printf("BAD2 in tp_attach, so 0x%x\n", so); + ENDDEBUG + so->so_pcb = 0; + +/*bad:*/ + IFDEBUG(D_CONN) + printf("BAD in tp_attach, so 0x%x\n", so); + ENDDEBUG + return error; +} + +/* + * NAME: tp_detach() + * + * CALLED FROM: + * tp.trans, on behalf of a user close request + * and when the reference timer goes off + * (if the disconnect was initiated by the protocol entity + * rather than by the user) + * + * FUNCTION and ARGUMENTS: + * remove the tpcb structure from the list of active or + * partially active connections, recycle all the mbufs + * associated with the pcb, ref structure, sockbufs, etc. + * Only free the ref structure if you know that a ref timer + * wasn't set for this tpcb. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + * tp_soisdisconnected() was already when this is called + */ +void +tp_detach(tpcb) + register struct tp_pcb *tpcb; +{ + void tp_freeref(), tp_rsyflush(); + register struct socket *so = tpcb->tp_sock; + + IFDEBUG(D_CONN) + printf("tp_detach(tpcb 0x%x, so 0x%x)\n", + tpcb,so); + ENDDEBUG + IFTRACE(D_CONN) + tptraceTPCB(TPPTmisc, "tp_detach tpcb so lsufx", + tpcb, so, *(u_short *)(tpcb->tp_lsuffix), 0); + ENDTRACE + + IFDEBUG(D_CONN) + printf("so_snd at 0x%x so_rcv at 0x%x\n", &so->so_snd, &so->so_rcv); + dump_mbuf(so->so_snd.sb_mb, "so_snd at detach "); + printf("about to call LL detach, nlproto 0x%x, nl_detach 0x%x\n", + tpcb->tp_nlproto, tpcb->tp_nlproto->nlp_pcbdetach); + ENDDEBUG + + if (tpcb->tp_Xsnd.sb_mb) { + printf("Unsent Xdata on detach; would panic"); + sbflush(&tpcb->tp_Xsnd); + } + if (tpcb->tp_ucddata) + m_freem(tpcb->tp_ucddata); + + IFDEBUG(D_CONN) + printf("reassembly info cnt %d rsyq 0x%x\n", + tpcb->tp_rsycnt, tpcb->tp_rsyq); + ENDDEBUG + if (tpcb->tp_rsyq) + tp_rsyflush(tpcb); + + if (tpcb->tp_next) { + remque(tpcb); + tpcb->tp_next = tpcb->tp_prev = 0; + } + tpcb->tp_notdetached = 0; + + IFDEBUG(D_CONN) + printf("calling (...nlproto->...)(0x%x, so 0x%x)\n", + tpcb->tp_npcb, so); + printf("so 0x%x so_head 0x%x, qlen %d q0len %d qlimit %d\n", + so, so->so_head, + so->so_q0len, so->so_qlen, so->so_qlimit); + ENDDEBUG + + (tpcb->tp_nlproto->nlp_pcbdetach)(tpcb->tp_npcb); + /* does an so->so_pcb = 0; sofree(so) */ + + IFDEBUG(D_CONN) + printf("after xxx_pcbdetach\n"); + ENDDEBUG + + if (tpcb->tp_state == TP_LISTENING) { + register struct tp_pcb **tt; + for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) + if (*tt == tpcb) + break; + if (*tt) + *tt = tpcb->tp_nextlisten; + else + printf("tp_detach from listen: should panic\n"); + } + if (tpcb->tp_refstate == REF_OPENING ) { + /* no connection existed here so no reference timer will be called */ + IFDEBUG(D_CONN) + printf("SETTING ref %d to REF_FREE\n", tpcb->tp_lref); + ENDDEBUG + + tp_freeref(tpcb->tp_lref); + } +#ifdef TP_PERF_MEAS + /* + * Get rid of the cluster mbuf allocated for performance measurements, if + * there is one. Note that tpcb->tp_perf_on says nothing about whether or + * not a cluster mbuf was allocated, so you have to check for a pointer + * to one (that is, we need the TP_PERF_MEASs around the following section + * of code, not the IFPERFs) + */ + if (tpcb->tp_p_mbuf) { + register struct mbuf *m = tpcb->tp_p_mbuf; + struct mbuf *n; + IFDEBUG(D_PERF_MEAS) + printf("freeing tp_p_meas 0x%x ", tpcb->tp_p_meas); + ENDDEBUG + do { + MFREE(m, n); + m = n; + } while (n); + tpcb->tp_p_meas = 0; + tpcb->tp_p_mbuf = 0; + } +#endif /* TP_PERF_MEAS */ + + IFDEBUG(D_CONN) + printf( "end of detach, NOT single, tpcb 0x%x\n", tpcb); + ENDDEBUG + /* free((caddr_t)tpcb, M_PCB); WHere to put this ? */ +} + +struct que { + struct tp_pcb *next; + struct tp_pcb *prev; +} tp_bound_pcbs = +{(struct tp_pcb *)&tp_bound_pcbs, (struct tp_pcb *)&tp_bound_pcbs}; + +u_short tp_unique; + +tp_tselinuse(tlen, tsel, siso, reuseaddr) +caddr_t tsel; +register struct sockaddr_iso *siso; +{ + struct tp_pcb *b = tp_bound_pcbs.next, *l = tp_listeners; + register struct tp_pcb *t; + + for (;;) { + if (b != (struct tp_pcb *)&tp_bound_pcbs) { + t = b; b = t->tp_next; + } else if (l) { + t = l; l = t->tp_nextlisten; + } else + break; + if (tlen == t->tp_lsuffixlen && bcmp(tsel, t->tp_lsuffix, tlen) == 0) { + if (t->tp_flags & TPF_GENERAL_ADDR) { + if (siso == 0 || reuseaddr == 0) + return 1; + } else if (siso) { + if (siso->siso_family == t->tp_domain && + t->tp_nlproto->nlp_cmpnetaddr(t->tp_npcb, siso, TP_LOCAL)) + return 1; + } else if (reuseaddr == 0) + return 1; + } + } + return 0; + +} + + +tp_pcbbind(tpcb, nam) +register struct tp_pcb *tpcb; +register struct mbuf *nam; +{ + register struct sockaddr_iso *siso = 0; + int tlen = 0, wrapped = 0; + caddr_t tsel; + u_short tutil; + + if (tpcb->tp_state != TP_CLOSED) + return (EINVAL); + if (nam) { + siso = mtod(nam, struct sockaddr_iso *); + switch (siso->siso_family) { + default: + return (EAFNOSUPPORT); +#ifdef ISO + case AF_ISO: + tlen = siso->siso_tlen; + tsel = TSEL(siso); + if (siso->siso_nlen == 0) + siso = 0; + break; +#endif +#ifdef INET + case AF_INET: + tsel = (caddr_t)&tutil; + if (tutil = ((struct sockaddr_in *)siso)->sin_port) { + tlen = 2; + } + if (((struct sockaddr_in *)siso)->sin_addr.s_addr == 0) + siso = 0; + } +#endif + } + if (tpcb->tp_lsuffixlen == 0) { + if (tlen) { + if (tp_tselinuse(tlen, tsel, siso, + tpcb->tp_sock->so_options & SO_REUSEADDR)) + return (EINVAL); + } else { + for (tsel = (caddr_t)&tutil, tlen = 2;;){ + if (tp_unique++ < ISO_PORT_RESERVED || + tp_unique > ISO_PORT_USERRESERVED) { + if (wrapped++) + return ESRCH; + tp_unique = ISO_PORT_RESERVED; + } + tutil = htons(tp_unique); + if (tp_tselinuse(tlen, tsel, siso, 0) == 0) + break; + } + if (siso) switch (siso->siso_family) { +#ifdef ISO + case AF_ISO: + bcopy(tsel, TSEL(siso), tlen); + siso->siso_tlen = tlen; + break; +#endif +#ifdef INET + case AF_INET: + ((struct sockaddr_in *)siso)->sin_port = tutil; +#endif + } + } + bcopy(tsel, tpcb->tp_lsuffix, (tpcb->tp_lsuffixlen = tlen)); + insque(tpcb, &tp_bound_pcbs); + } else { + if (tlen || siso == 0) + return (EINVAL); + } + if (siso == 0) { + tpcb->tp_flags |= TPF_GENERAL_ADDR; + return (0); + } + return tpcb->tp_nlproto->nlp_pcbbind(tpcb->tp_npcb, nam); +} diff --git a/sys/netiso/tp_pcb.h b/sys/netiso/tp_pcb.h new file mode 100644 index 0000000..0353cb4 --- /dev/null +++ b/sys/netiso/tp_pcb.h @@ -0,0 +1,356 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_pcb.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_pcb.h,v 5.2 88/11/18 17:09:32 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_pcb.h,v $ + * + * + * This file defines the transport protocol control block (tpcb). + * and a bunch of #define values that are used in the tpcb. + */ + +#ifndef __TP_PCB__ +#define __TP_PCB__ + +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_user.h> +#ifndef sblock +#include <sys/socketvar.h> +#endif /* sblock */ + +/* NOTE: the code depends on REF_CLOSED > REF_OPEN > the rest, and + * on REF_FREE being zero + * + * Possible improvement: + * think about merging the tp_ref w/ the tpcb and doing a search + * through the tpcb list, from tpb. This would slow down lookup + * during data transfer + * It would be a little nicer also to have something based on the + * clock (like top n bits of the reference is part of the clock, to + * minimize the likelihood of reuse after a crash) + * also, need to keep the timer servicing part to a minimum (although + * the cost of this is probably independent of whether the timers are + * in the pcb or in an array.. + * Last, would have to make the number of timers a function of the amount of + * mbufs available, plus some for the frozen references. + * + * Possible improvement: + * Might not need the ref_state stuff either... + * REF_FREE could correspond to tp_state == CLOSED or nonexistend tpcb, + * REF_OPEN to tp_state anywhere from AK_WAIT or CR_SENT to CLOSING + * REF_OPENING could correspond to LISTENING, because that's the + * way it's used, not because the correspondence is exact. + * REF_CLOSED could correspond to REFWAIT + */ +#define REF_FROZEN 3 /* has ref timer only */ +#define REF_OPEN 2 /* has timers, possibly active */ +#define REF_OPENING 1 /* in use (has a pcb) but no timers */ +#define REF_FREE 0 /* free to reallocate */ + +#define TM_NTIMERS 6 + +struct tp_ref { + struct tp_pcb *tpr_pcb; /* back ptr to PCB */ +}; + +/* PER system stuff (one static structure instead of a bunch of names) */ +struct tp_refinfo { + struct tp_ref *tpr_base; + int tpr_size; + int tpr_maxopen; + int tpr_numopen; +}; + +struct nl_protosw { + int nlp_afamily; /* address family */ + int (*nlp_putnetaddr)(); /* puts addresses in nl pcb */ + int (*nlp_getnetaddr)(); /* gets addresses from nl pcb */ + int (*nlp_cmpnetaddr)(); /* compares address in pcb with sockaddr */ + int (*nlp_putsufx)(); /* puts transport suffixes in nl pcb */ + int (*nlp_getsufx)(); /* gets transport suffixes from nl pcb */ + int (*nlp_recycle_suffix)();/* clears suffix from nl pcb */ + int (*nlp_mtu)(); /* figures out mtu based on nl used */ + int (*nlp_pcbbind)(); /* bind to pcb for net level */ + int (*nlp_pcbconn)(); /* connect for net level */ + int (*nlp_pcbdisc)(); /* disconnect net level */ + int (*nlp_pcbdetach)(); /* detach net level pcb */ + int (*nlp_pcballoc)(); /* allocate a net level pcb */ + int (*nlp_output)(); /* prepare a packet to give to nl */ + int (*nlp_dgoutput)(); /* prepare a packet to give to nl */ + int (*nlp_ctloutput)(); /* hook for network set/get options */ + caddr_t nlp_pcblist; /* list of xx_pcb's for connections */ +}; + + +struct tp_pcb { + struct tp_pcb *tp_next; + struct tp_pcb *tp_prev; + struct tp_pcb *tp_nextlisten; /* chain all listeners */ + struct socket *tp_sock; /* back ptr */ + u_short tp_state; /* state of fsm */ + short tp_retrans; /* # times can still retrans */ + caddr_t tp_npcb; /* to lower layer pcb */ + struct nl_protosw *tp_nlproto; /* lower-layer dependent routines */ + struct rtentry **tp_routep; /* obtain mtu; inside npcb */ + + + RefNum tp_lref; /* local reference */ + RefNum tp_fref; /* foreign reference */ + + u_int tp_seqmask; /* mask for seq space */ + u_int tp_seqbit; /* bit for seq number wraparound */ + u_int tp_seqhalf; /* half the seq space */ + + struct mbuf *tp_ucddata; /* user connect/disconnect data */ + + /* credit & sequencing info for SENDING */ + u_short tp_fcredit; /* current remote credit in # packets */ + u_short tp_maxfcredit; /* max remote credit in # packets */ + u_short tp_dupacks; /* intuit packet loss before rxt timo */ + u_long tp_cong_win; /* congestion window in bytes. + * see profuse comments in TCP code + */ + u_long tp_ssthresh; /* cong_win threshold for slow start + * exponential to linear switch + */ + SeqNum tp_snduna; /* seq # of lowest unacked DT */ + SeqNum tp_sndnew; /* seq # of lowest unsent DT */ + SeqNum tp_sndnum; /* next seq # to be assigned */ + SeqNum tp_sndnxt; /* what to do next; poss. rxt */ + struct mbuf *tp_sndnxt_m; /* packet corres. to sndnxt*/ + int tp_Nwindow; /* for perf. measurement */ + + /* credit & sequencing info for RECEIVING */ + SeqNum tp_rcvnxt; /* next DT seq # expect to recv */ + SeqNum tp_sent_lcdt; /* cdt according to last ack sent */ + SeqNum tp_sent_uwe; /* uwe according to last ack sent */ + SeqNum tp_sent_rcvnxt; /* rcvnxt according to last ack sent + * needed for perf measurements only + */ + u_short tp_lcredit; /* current local credit in # packets */ + u_short tp_maxlcredit; /* needed for reassembly queue */ + struct mbuf **tp_rsyq; /* unacked stuff recvd out of order */ + int tp_rsycnt; /* number of packets "" "" "" "" */ + u_long tp_rhiwat; /* remember original RCVBUF size */ + + /* receiver congestion state stuff ... */ + u_int tp_win_recv; + + /* receive window as a scaled int (8 bit fraction part) */ + + struct cong_sample { + ushort cs_size; /* current window size */ + ushort cs_received; /* PDUs received in this sample */ + ushort cs_ce_set; /* PDUs received in this sample with CE bit set */ + } tp_cong_sample; + + + /* parameters per-connection controllable by user */ + struct tp_conn_param _tp_param; + +#define tp_Nretrans _tp_param.p_Nretrans +#define tp_dr_ticks _tp_param.p_dr_ticks +#define tp_cc_ticks _tp_param.p_cc_ticks +#define tp_dt_ticks _tp_param.p_dt_ticks +#define tp_xpd_ticks _tp_param.p_x_ticks +#define tp_cr_ticks _tp_param.p_cr_ticks +#define tp_keepalive_ticks _tp_param.p_keepalive_ticks +#define tp_sendack_ticks _tp_param.p_sendack_ticks +#define tp_refer_ticks _tp_param.p_ref_ticks +#define tp_inact_ticks _tp_param.p_inact_ticks +#define tp_xtd_format _tp_param.p_xtd_format +#define tp_xpd_service _tp_param.p_xpd_service +#define tp_ack_strat _tp_param.p_ack_strat +#define tp_rx_strat _tp_param.p_rx_strat +#define tp_use_checksum _tp_param.p_use_checksum +#define tp_use_efc _tp_param.p_use_efc +#define tp_use_nxpd _tp_param.p_use_nxpd +#define tp_use_rcc _tp_param.p_use_rcc +#define tp_tpdusize _tp_param.p_tpdusize +#define tp_class _tp_param.p_class +#define tp_winsize _tp_param.p_winsize +#define tp_no_disc_indications _tp_param.p_no_disc_indications +#define tp_dont_change_params _tp_param.p_dont_change_params +#define tp_netservice _tp_param.p_netservice +#define tp_version _tp_param.p_version +#define tp_ptpdusize _tp_param.p_ptpdusize + + int tp_l_tpdusize; + /* whereas tp_tpdusize is log2(the negotiated max size) + * l_tpdusize is the size we'll use when sending, in # chars + */ + + int tp_rtv; /* max round-trip time variance */ + int tp_rtt; /* smoothed round-trip time */ + SeqNum tp_rttseq; /* packet being timed */ + int tp_rttemit; /* when emitted, in ticks */ + int tp_idle; /* last activity, in ticks */ + short tp_rxtcur; /* current retransmit value */ + short tp_rxtshift; /* log(2) of rexmt exp. backoff */ + u_char tp_cebit_off; /* real DEC bit algorithms not in use */ + u_char tp_oktonagle; /* Last unsent pckt may be append to */ + u_char tp_flags; /* values: */ +#define TPF_NLQOS_PDN TPFLAG_NLQOS_PDN +#define TPF_PEER_ON_SAMENET TPFLAG_PEER_ON_SAMENET +#define TPF_GENERAL_ADDR TPFLAG_GENERAL_ADDR +#define TPF_DELACK 0x8 +#define TPF_ACKNOW 0x10 + +#define PEER_IS_LOCAL(t) (((t)->tp_flags & TPF_PEER_ON_SAME_NET) != 0) +#define USES_PDN(t) (((t)->tp_flags & TPF_NLQOS_PDN) != 0) + + + unsigned + tp_sendfcc:1, /* shall next ack include FCC parameter? */ + tp_trace:1, /* is this pcb being traced? (not used yet) */ + tp_perf_on:1, /* 0/1 -> performance measuring on */ + tp_reneged:1, /* have we reneged on cdt since last ack? */ + tp_decbit:3, /* dec bit was set, we're in reneg mode */ + tp_notdetached:1; /* Call tp_detach before freeing XXXXXXX */ + +#ifdef TP_PERF_MEAS + /* performance stats - see tp_stat.h */ + struct tp_pmeas *tp_p_meas; + struct mbuf *tp_p_mbuf; +#endif /* TP_PERF_MEAS */ + + /* addressing */ + u_short tp_domain; /* domain (INET, ISO) */ + /* for compatibility with the *old* way and with INET, be sure that + * that lsuffix and fsuffix are aligned to a short addr. + * having them follow the u_short *suffixlen should suffice (choke) + */ + u_short tp_fsuffixlen; /* foreign suffix */ + char tp_fsuffix[MAX_TSAP_SEL_LEN]; + u_short tp_lsuffixlen; /* local suffix */ + char tp_lsuffix[MAX_TSAP_SEL_LEN]; +#define SHORT_LSUFXP(tpcb) ((short *)((tpcb)->tp_lsuffix)) +#define SHORT_FSUFXP(tpcb) ((short *)((tpcb)->tp_fsuffix)) + + /* Timer stuff */ + u_char tp_vers; /* protocol version */ + u_char tp_peer_acktime; /* used for DT retrans time */ + u_char tp_refstate; /* values REF_FROZEN, etc. above */ + struct tp_pcb *tp_fasttimeo; /* limit pcbs to examine */ + u_int tp_timer[TM_NTIMERS]; /* C timers */ + + struct sockbuf tp_Xsnd; /* for expedited data */ +/* struct sockbuf tp_Xrcv; /* for expedited data */ +#define tp_Xrcv tp_sock->so_rcv + SeqNum tp_Xsndnxt; /* next XPD seq # to send */ + SeqNum tp_Xuna; /* seq # of unacked XPD */ + SeqNum tp_Xrcvnxt; /* next XPD seq # expect to recv */ + + /* AK subsequencing */ + u_short tp_s_subseq; /* next subseq to send */ + u_short tp_r_subseq; /* highest recv subseq */ + +}; + +u_int tp_start_win; + +#define ROUND(scaled_int) (((scaled_int) >> 8) + (((scaled_int) & 0x80) ? 1:0)) + +/* to round off a scaled int with an 8 bit fraction part */ + +#define CONG_INIT_SAMPLE(pcb) \ + pcb->tp_cong_sample.cs_received = \ + pcb->tp_cong_sample.cs_ce_set = 0; \ + pcb->tp_cong_sample.cs_size = max(pcb->tp_lcredit, 1) << 1; + +#define CONG_UPDATE_SAMPLE(pcb, ce_bit) \ + pcb->tp_cong_sample.cs_received++; \ + if (ce_bit) { \ + pcb->tp_cong_sample.cs_ce_set++; \ + } \ + if (pcb->tp_cong_sample.cs_size <= pcb->tp_cong_sample.cs_received) { \ + if ((pcb->tp_cong_sample.cs_ce_set << 1) >= \ + pcb->tp_cong_sample.cs_size ) { \ + pcb->tp_win_recv -= pcb->tp_win_recv >> 3; /* multiply by .875 */ \ + pcb->tp_win_recv = max(1 << 8, pcb->tp_win_recv); \ + } \ + else { \ + pcb->tp_win_recv += (1 << 8); /* add one to the scaled int */ \ + } \ + pcb->tp_lcredit = ROUND(pcb->tp_win_recv); \ + CONG_INIT_SAMPLE(pcb); \ + } + +#ifdef KERNEL +extern struct tp_refinfo tp_refinfo; +extern struct timeval time; +extern struct tp_ref *tp_ref; +extern struct tp_param tp_param; +extern struct nl_protosw nl_protosw[]; +extern struct tp_pcb *tp_listeners; +extern struct tp_pcb *tp_ftimeolist; +#endif + +#define sototpcb(so) ((struct tp_pcb *)(so->so_pcb)) +#define sototpref(so) ((sototpcb(so)->tp_ref)) +#define tpcbtoso(tp) ((struct socket *)((tp)->tp_sock)) +#define tpcbtoref(tp) ((struct tp_ref *)((tp)->tp_ref)) + +#endif /* __TP_PCB__ */ diff --git a/sys/netiso/tp_seq.h b/sys/netiso/tp_seq.h new file mode 100644 index 0000000..f14e5ae --- /dev/null +++ b/sys/netiso/tp_seq.h @@ -0,0 +1,124 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_seq.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_seq.h,v 5.1 88/10/12 12:20:59 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_seq.h,v $ + * + * These macros perform sequence number arithmetic modulo (2**7 or 2**31). + * The relevant fields in the tpcb are: + * tp_seqmask : the mask of bits that define the sequence space. + * tp_seqbit : 1 + tp_seqmask + * tp_seqhalf : tp_seqbit / 2 or half the sequence space (rounded up) + * Not exactly fast, but at least it's maintainable. + */ + +#ifndef __TP_SEQ__ +#define __TP_SEQ__ + +#define SEQ(tpcb,x) \ + ((x) & (tpcb)->tp_seqmask) + +#define SEQ_GT(tpcb, seq, operand ) \ +( ((int)((seq)-(operand)) > 0)\ +? ((int)((seq)-(operand)) < (int)(tpcb)->tp_seqhalf)\ +: !(-((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) + +#define SEQ_GEQ(tpcb, seq, operand ) \ +( ((int)((seq)-(operand)) >= 0)\ +? ((int)((seq)-(operand)) < (int)(tpcb)->tp_seqhalf)\ +: !((-((int)(seq)-(operand))) < (int)(tpcb)->tp_seqhalf)) + +#define SEQ_LEQ(tpcb, seq, operand ) \ +( ((int)((seq)-(operand)) <= 0)\ +? ((-(int)((seq)-(operand))) < (int)(tpcb)->tp_seqhalf)\ +: !(((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) + +#define SEQ_LT(tpcb, seq, operand ) \ +( ((int)((seq)-(operand)) < 0)\ +? ((-(int)((seq)-(operand))) < (int)(tpcb)->tp_seqhalf)\ +: !(((int)(seq)-(operand)) < (int)(tpcb)->tp_seqhalf)) + +#define SEQ_MIN(tpcb, a, b) ( SEQ_GT(tpcb, a, b) ? b : a) + +#define SEQ_MAX(tpcb, a, b) ( SEQ_GT(tpcb, a, b) ? a : b) + +#define SEQ_INC(tpcb, Seq) ((++Seq), ((Seq) &= (tpcb)->tp_seqmask)) + +#define SEQ_DEC(tpcb, Seq)\ + ((Seq) = (((Seq)+(unsigned)((int)(tpcb)->tp_seqbit - 1))&(tpcb)->tp_seqmask)) + +/* (amt) had better be less than the seq bit ! */ + +#define SEQ_SUB(tpcb, Seq, amt)\ + (((Seq) + (unsigned)((int)(tpcb)->tp_seqbit - amt)) & (tpcb)->tp_seqmask) +#define SEQ_ADD(tpcb, Seq, amt) (((Seq) + (unsigned)amt) & (tpcb)->tp_seqmask) + + +#define IN_RWINDOW(tpcb, seq, lwe, uwe)\ + ( SEQ_GEQ(tpcb, seq, lwe) && SEQ_LT(tpcb, seq, uwe) ) + +#define IN_SWINDOW(tpcb, seq, lwe, uwe)\ + ( SEQ_GT(tpcb, seq, lwe) && SEQ_LEQ(tpcb, seq, uwe) ) + +#endif /* __TP_SEQ__ */ diff --git a/sys/netiso/tp_stat.h b/sys/netiso/tp_stat.h new file mode 100644 index 0000000..bf6e1a5 --- /dev/null +++ b/sys/netiso/tp_stat.h @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_stat.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_stat.h,v 5.4 88/11/18 17:28:38 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_stat.h,v $ + * + * Here are the data structures in which the global + * statistics(counters) are gathered. + */ + +#ifndef __TP_STAT__ +#define __TP_STAT__ + +struct tp_stat { + u_long ts_param_ignored; + u_long ts_unused3; + u_long ts_bad_csum; + + u_long ts_inv_length; + u_long ts_inv_pcode; + u_long ts_inv_dutype; + u_long ts_negotfailed; + u_long ts_inv_dref; + u_long ts_inv_pval; + u_long ts_inv_sufx; + u_long ts_inv_aclass; + + u_long ts_xtd_fmt; + u_long ts_use_txpd; + u_long ts_csum_off; + u_long ts_send_drop; + u_long ts_recv_drop; + + u_long ts_xpd_intheway;/* xpd mark caused data flow to stop */ + u_long ts_xpdmark_del; /* xpd markers thrown away */ + u_long ts_dt_ooo; /* dt tpdus received out of order */ + u_long ts_dt_niw; /* dt tpdus received & not in window */ + u_long ts_xpd_niw; /* xpd tpdus received & not in window */ + u_long ts_xpd_dup; + u_long ts_dt_dup; /* dt tpdus received & are duplicates */ + + u_long ts_zfcdt; /* # times f credit went down to 0 */ + u_long ts_lcdt_reduced; /* + # times local cdt reduced on an acknowledgement. + */ + + u_long ts_pkt_rcvd; /* from ip */ + u_long ts_tpdu_rcvd; /* accepted as a TPDU in tp_input */ + u_long ts_tpdu_sent; + u_long ts_unused2; + + u_long ts_retrans_cr; + u_long ts_retrans_cc; + u_long ts_retrans_dr; + u_long ts_retrans_dt; + u_long ts_retrans_xpd; + u_long ts_conn_gaveup; + + u_long ts_ER_sent; + u_long ts_DT_sent; + u_long ts_XPD_sent; + u_long ts_AK_sent; + u_long ts_XAK_sent; + u_long ts_DR_sent; + u_long ts_DC_sent; + u_long ts_CR_sent; + u_long ts_CC_sent; + + u_long ts_ER_rcvd; + u_long ts_DT_rcvd; + u_long ts_XPD_rcvd; + u_long ts_AK_rcvd; + u_long ts_XAK_rcvd; + u_long ts_DR_rcvd; + u_long ts_DC_rcvd; + u_long ts_CR_rcvd; + u_long ts_CC_rcvd; + + u_long ts_Eticks; + u_long ts_Eexpired; + u_long ts_Eset; + u_long ts_Ecan_act; + u_long ts_Cticks; + u_long ts_Cexpired; + u_long ts_Cset; + u_long ts_Ccan_act; + u_long ts_Ccan_inact; + u_long ts_Fdelack; + u_long ts_Fpruned; + + u_long ts_concat_rcvd; + + u_long ts_zdebug; /* zero dref to test timeout on conn estab tp_input.c */ + u_long ts_ydebug; /* throw away pseudo-random pkts tp_input.c */ + u_long ts_unused5; + u_long ts_unused; /* kludged concat to test separation tp_emit.c */ + u_long ts_vdebug; /* kludge to test input size checking tp_emit.c */ + u_long ts_unused4; + u_long ts_ldebug; /* faked a renegging of credit */ + + u_long ts_mb_small; + u_long ts_mb_cluster; + u_long ts_mb_len_distr[17]; + + u_long ts_eot_input; + u_long ts_eot_user; + u_long ts_EOT_sent; + u_long ts_tp0_conn; + u_long ts_tp4_conn; + u_long ts_quench; + u_long ts_rcvdecbit; + +#define NRTT_CATEGORIES 4 + /* The 4 categories are: + * 0 --> tp_flags: ~TPF_PEER_ON_SAMENET | TPF_NL_PDN + * 1 --> tp_flags: ~TPF_PEER_ON_SAMENET | ~TPF_NL_PDN + * 2 --> tp_flags: TPF_PEER_ON_SAMENET | ~TPF_NL_PDN + * 3 --> tp_flags: TPF_PEER_ON_SAMENET | TPF_NL_PDN + */ + int ts_rtt[NRTT_CATEGORIES]; + int ts_rtv[NRTT_CATEGORIES]; + + u_long ts_ackreason[_ACK_NUM_REASONS_]; + /* ACK_DONT 0 / ACK_STRAT_EACH 0x1 / ACK_STRAT_FULLWIN 0x4 + * ACK_DUP 0x8 / ACK_EOT 0x10 / ACK_REORDER 0x20 + * ACK_USRRCV ** + * ACK_FCC ** + */ +} tp_stat ; +#define TP_PM_MAX 0xa /* 10 decimal */ + +#define IncStat(x) tp_stat./**/x/**/++ + +#ifdef TP_PERF_MEAS + +#define PStat(Tpcb, X) (Tpcb)->tp_p_meas->/**/X/**/ +#define IncPStat(Tpcb, X) if((Tpcb)->tp_perf_on) (Tpcb)->tp_p_meas->/**/X/**/++ + +/* BEWARE OF MACROS like this ^^^ must be sure it's surrounded by {} if + * it's used in an if-else statement. + */ + + +/* for perf measurement stuff: maximum window size it can handle */ + +struct tp_pmeas { + /* the first few are distributions as a fn of window size + * only keep enough space for normal format plus 1 slot for + * extended format, in case any windows larger than 15 are used + */ + + /* + * tps_npdusent: for each call to tp_sbsend, we inc the + * element representing the number of pdus sent in this call + */ + int tps_win_lim_by_cdt[TP_PM_MAX+1]; + int tps_win_lim_by_data[TP_PM_MAX+1]; + /* + * tps_sendtime: Each call to tp_sbsend() is timed. For + * Each window size, we keep the running average of the time + * taken by tp_sbsend() for each window size. + */ + int tps_sendtime[TP_PM_MAX+1]; + /* + * n_TMsendack: # times ack sent because timer went off + * n_ack_cuz_eot: # times ack sent due to EOTSDU on incoming packet + * n_ack_cuz_dup: # times ack sent for receiving a duplicate pkt. + * n_ack_cuz_fullwin: # times ack sent for receiving the full window. + * n_ack_cuz_doack: # times ack sent for having just reordered data. + */ + int tps_n_TMsendack; + int tps_n_ack_cuz_eot; + int tps_n_ack_cuz_fullwin; + int tps_n_ack_cuz_reorder; + int tps_n_ack_cuz_dup; + int tps_n_ack_cuz_strat; + /* + * when we send an ack: how much less than the "expected" window + * did we actually ack. For example: if we last sent a credit + * of 10, and we're acking now for whatever reason, and have + * only received 6 since our last credit advertisement, we'll + * keep the difference, 4, in this variable. + */ + int tps_ack_early[TP_PM_MAX+1]; + /* + * when we ack, for the # pkts we actually acked w/ this ack, + * how much cdt are we advertising? + * [ size of window acknowledged ] [ cdt we're giving ] + */ + int tps_cdt_acked[TP_PM_MAX+1][TP_PM_MAX+1]; + + int tps_AK_sent; + int tps_XAK_sent; + int tps_DT_sent; + int tps_XPD_sent; + int tps_AK_rcvd; + int tps_XAK_rcvd; + int tps_DT_rcvd; + int tps_XPD_rcvd; + + int Nb_from_sess; + int Nb_to_sess; + int Nb_to_ll; + int Nb_from_ll; +}; + +#define IFPERF(tpcb) if (tpcb->tp_perf_on && tpcb->tp_p_meas) { +#define ENDPERF } + +#else + +int PStat_Junk; +#define PStat(tpcb, x) PStat_Junk +#define IncPStat(tpcb, x) /* no-op */ +#define tpmeas(a,b,c,d,e,f) 0 + +#define IFPERF(x) if (0) { +#define ENDPERF } + +#endif /* TP_PERF_MEAS */ + +#endif /* __TP_STAT__ */ diff --git a/sys/netiso/tp_states.h b/sys/netiso/tp_states.h new file mode 100644 index 0000000..ac6213a --- /dev/null +++ b/sys/netiso/tp_states.h @@ -0,0 +1,13 @@ +/* $Header$ */ +/* $Source$ */ +#define ST_ERROR 0x0 +#define TP_CLOSED 0x1 +#define TP_CRSENT 0x2 +#define TP_AKWAIT 0x3 +#define TP_OPEN 0x4 +#define TP_CLOSING 0x5 +#define TP_REFWAIT 0x6 +#define TP_LISTENING 0x7 +#define TP_CONFIRMING 0x8 + +#define tp_NSTATES 0x9 diff --git a/sys/netiso/tp_states.init b/sys/netiso/tp_states.init new file mode 100644 index 0000000..89e5345 --- /dev/null +++ b/sys/netiso/tp_states.init @@ -0,0 +1,75 @@ +/* $Header$ */ +/* $Source$ */ +{0x3,0x0}, +{0x6,0x1}, +{0x6,0x2}, +{0x6,0x0}, +{0x2,0x3}, +{0x2,0x0}, +{0x1,0x0}, +{0x5,0x0}, +{0x4,0x0}, +{0x7,0x0}, +{0x7,0x0}, +{0x1,0x4}, +{0x8,0x5}, +{0x8,0x6}, +{0x4,0x7}, +{0x3,0x8}, +{0x1,0x9}, +{0x2,0xa}, +{0x6,0xb}, +{0x1,0xc}, +{0x6,0xd}, +{0x6,0xe}, +{0x6,0xf}, +{0x6,0x10}, +{0x1,0x11}, +{0x6,0x12}, +{0x5,0x13}, +{0x4,0x14}, +{0x4,0x15}, +{0x2,0x16}, +{0x6,0x17}, +{0x3,0x18}, +{0x4,0x19}, +{0x4,0x1a}, +{0x4,0x1b}, +{0x3,0x1c}, +{0x4,0x1c}, +{0x4,0x1d}, +{0x4,0x1e}, +{0x4,0x1f}, +{0x4,0x20}, +{0x3,0x20}, +{0x6,0x21}, +{0x5,0x22}, +{0x6,0x23}, +{0x5,0x24}, +{0x3,0x25}, +{0x5,0x26}, +{0x5,0x27}, +{0x4,0x28}, +{0x4,0x29}, +{0x5,0x2a}, +{0x6,0x2b}, +{0x1,0x2c}, +{0x4,0x2d}, +{0x4,0x2e}, +{0x4,0x2f}, +{0x4,0x30}, +{0x4,0x31}, +{0x4,0x32}, +{0x4,0x33}, +{0x4,0x34}, +{0x4,0x35}, +{0x4,0x36}, +{0x6,0x37}, +{0x6,0x38}, +{0x7,0x0}, +{0x5,0x0}, +{0x3,0x0}, +{0x2,0x0}, +{0x4,0x0}, +{0x6,0x0}, +{0x1,0x0}, diff --git a/sys/netiso/tp_subr.c b/sys/netiso/tp_subr.c new file mode 100644 index 0000000..1259ee4 --- /dev/null +++ b/sys/netiso/tp_subr.c @@ -0,0 +1,947 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_subr.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_subr.c,v 5.3 88/11/18 17:28:43 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_subr.c,v $ + * + * The main work of data transfer is done here. + * These routines are called from tp.trans. + * They include the routines that check the validity of acks and Xacks, + * (tp_goodack() and tp_goodXack() ) + * take packets from socket buffers and send them (tp_send()), + * drop the data from the socket buffers (tp_sbdrop()), + * and put incoming packet data into socket buffers (tp_stash()). + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <netiso/tp_ip.h> +#include <netiso/iso.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_param.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_meas.h> +#include <netiso/tp_seq.h> + +int tp_emit(), tp_sbdrop(); +int tprexmtthresh = 3; +extern int ticks; +void tp_send(); + +/* + * CALLED FROM: + * tp.trans, when an XAK arrives + * FUNCTION and ARGUMENTS: + * Determines if the sequence number (seq) from the XAK + * acks anything new. If so, drop the appropriate tpdu + * from the XPD send queue. + * RETURN VALUE: + * Returns 1 if it did this, 0 if the ack caused no action. + */ +int +tp_goodXack(tpcb, seq) + struct tp_pcb *tpcb; + SeqNum seq; +{ + + IFTRACE(D_XPD) + tptraceTPCB(TPPTgotXack, + seq, tpcb->tp_Xuna, tpcb->tp_Xsndnxt, tpcb->tp_sndnew, + tpcb->tp_snduna); + ENDTRACE + + if ( seq == tpcb->tp_Xuna ) { + tpcb->tp_Xuna = tpcb->tp_Xsndnxt; + + /* DROP 1 packet from the Xsnd socket buf - just so happens + * that only one packet can be there at any time + * so drop the whole thing. If you allow > 1 packet + * the socket buffer, then you'll have to keep + * track of how many characters went w/ each XPD tpdu, so this + * will get messier + */ + IFDEBUG(D_XPD) + dump_mbuf(tpcb->tp_Xsnd.sb_mb, + "tp_goodXack Xsnd before sbdrop"); + ENDDEBUG + + IFTRACE(D_XPD) + tptraceTPCB(TPPTmisc, + "goodXack: dropping cc ", + (int)(tpcb->tp_Xsnd.sb_cc), + 0,0,0); + ENDTRACE + sbdroprecord(&tpcb->tp_Xsnd); + return 1; + } + return 0; +} + +/* + * CALLED FROM: + * tp_good_ack() + * FUNCTION and ARGUMENTS: + * updates + * smoothed average round trip time (*rtt) + * roundtrip time variance (*rtv) - actually deviation, not variance + * given the new value (diff) + * RETURN VALUE: + * void + */ + +void +tp_rtt_rtv(tpcb) +register struct tp_pcb *tpcb; +{ + int old = tpcb->tp_rtt; + int delta, elapsed = ticks - tpcb->tp_rttemit; + + if (tpcb->tp_rtt != 0) { + /* + * rtt is the smoothed round trip time in machine clock ticks (hz). + * It is stored as a fixed point number, unscaled (unlike the tcp + * srtt). The rationale here is that it is only significant to the + * nearest unit of slowtimo, which is at least 8 machine clock ticks + * so there is no need to scale. The smoothing is done according + * to the same formula as TCP (rtt = rtt*7/8 + measured_rtt/8). + */ + delta = elapsed - tpcb->tp_rtt; + if ((tpcb->tp_rtt += (delta >> TP_RTT_ALPHA)) <= 0) + tpcb->tp_rtt = 1; + /* + * rtv is a smoothed accumulated mean difference, unscaled + * for reasons expressed above. + * It is smoothed with an alpha of .75, and the round trip timer + * will be set to rtt + 4*rtv, also as TCP does. + */ + if (delta < 0) + delta = -delta; + if ((tpcb->tp_rtv += ((delta - tpcb->tp_rtv) >> TP_RTV_ALPHA)) <= 0) + tpcb->tp_rtv = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt) + */ + tpcb->tp_rtt = elapsed; + tpcb->tp_rtv = elapsed >> 1; + } + tpcb->tp_rttemit = 0; + tpcb->tp_rxtshift = 0; + /* + * Quoting TCP: "the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks)." + */ + TP_RANGESET(tpcb->tp_dt_ticks, TP_REXMTVAL(tpcb), + tpcb->tp_peer_acktime, 128 /* XXX */); + IFDEBUG(D_RTT) + printf("%s tpcb 0x%x, elapsed %d, delta %d, rtt %d, rtv %d, old %d\n", + "tp_rtt_rtv:",tpcb,elapsed,delta,tpcb->tp_rtt,tpcb->tp_rtv,old); + ENDDEBUG + tpcb->tp_rxtcur = tpcb->tp_dt_ticks; +} + +/* + * CALLED FROM: + * tp.trans when an AK arrives + * FUNCTION and ARGUMENTS: + * Given (cdt), the credit from the AK tpdu, and + * (seq), the sequence number from the AK tpdu, + * tp_goodack() determines if the AK acknowledges something in the send + * window, and if so, drops the appropriate packets from the retransmission + * list, computes the round trip time, and updates the retransmission timer + * based on the new smoothed round trip time. + * RETURN VALUE: + * Returns 1 if + * EITHER it actually acked something heretofore unacknowledged + * OR no news but the credit should be processed. + * If something heretofore unacked was acked with this sequence number, + * the appropriate tpdus are dropped from the retransmission control list, + * by calling tp_sbdrop(). + * No need to see the tpdu itself. + */ +int +tp_goodack(tpcb, cdt, seq, subseq) + register struct tp_pcb *tpcb; + u_int cdt; + register SeqNum seq; + u_int subseq; +{ + int old_fcredit; + int bang = 0; /* bang --> ack for something heretofore unacked */ + u_int bytes_acked; + + IFDEBUG(D_ACKRECV) + printf("goodack tpcb 0x%x seq 0x%x cdt %d una 0x%x new 0x%x nxt 0x%x\n", + tpcb, seq, cdt, tpcb->tp_snduna, tpcb->tp_sndnew, tpcb->tp_sndnxt); + ENDDEBUG + IFTRACE(D_ACKRECV) + tptraceTPCB(TPPTgotack, + seq,cdt, tpcb->tp_snduna,tpcb->tp_sndnew,subseq); + ENDTRACE + + IFPERF(tpcb) + tpmeas(tpcb->tp_lref, TPtime_ack_rcvd, (struct timeval *)0, seq, 0, 0); + ENDPERF + + if (seq == tpcb->tp_snduna) { + if (subseq < tpcb->tp_r_subseq || + (subseq == tpcb->tp_r_subseq && cdt <= tpcb->tp_fcredit)) { + discard_the_ack: + IFDEBUG(D_ACKRECV) + printf("goodack discard : tpcb 0x%x subseq %d r_subseq %d\n", + tpcb, subseq, tpcb->tp_r_subseq); + ENDDEBUG + goto done; + } + if (cdt == tpcb->tp_fcredit /*&& thus subseq > tpcb->tp_r_subseq */) { + tpcb->tp_r_subseq = subseq; + if (tpcb->tp_timer[TM_data_retrans] == 0) + tpcb->tp_dupacks = 0; + else if (++tpcb->tp_dupacks == tprexmtthresh) { + /* partner went out of his way to signal with different + subsequences that he has the same lack of an expected + packet. This may be an early indiciation of a loss */ + + SeqNum onxt = tpcb->tp_sndnxt; + struct mbuf *onxt_m = tpcb->tp_sndnxt_m; + u_int win = min(tpcb->tp_fcredit, + tpcb->tp_cong_win / tpcb->tp_l_tpdusize) / 2; + IFDEBUG(D_ACKRECV) + printf("%s tpcb 0x%x seq 0x%x rttseq 0x%x onxt 0x%x\n", + "goodack dupacks:", tpcb, seq, tpcb->tp_rttseq, onxt); + ENDDEBUG + if (win < 2) + win = 2; + tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; + tpcb->tp_timer[TM_data_retrans] = 0; + tpcb->tp_rttemit = 0; + tpcb->tp_sndnxt = tpcb->tp_snduna; + tpcb->tp_sndnxt_m = 0; + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; + tp_send(tpcb); + tpcb->tp_cong_win = tpcb->tp_ssthresh + + tpcb->tp_dupacks * tpcb->tp_l_tpdusize; + if (SEQ_GT(tpcb, onxt, tpcb->tp_sndnxt)) { + tpcb->tp_sndnxt = onxt; + tpcb->tp_sndnxt_m = onxt_m; + } + + } else if (tpcb->tp_dupacks > tprexmtthresh) { + tpcb->tp_cong_win += tpcb->tp_l_tpdusize; + } + goto done; + } + } else if (SEQ_LT(tpcb, seq, tpcb->tp_snduna)) + goto discard_the_ack; + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tpcb->tp_dupacks > tprexmtthresh && + tpcb->tp_cong_win > tpcb->tp_ssthresh) + tpcb->tp_cong_win = tpcb->tp_ssthresh; + tpcb->tp_r_subseq = subseq; + old_fcredit = tpcb->tp_fcredit; + tpcb->tp_fcredit = cdt; + if (cdt > tpcb->tp_maxfcredit) + tpcb->tp_maxfcredit = cdt; + tpcb->tp_dupacks = 0; + + if (IN_SWINDOW(tpcb, seq, tpcb->tp_snduna, tpcb->tp_sndnew)) { + + tpsbcheck(tpcb, 0); + bytes_acked = tp_sbdrop(tpcb, seq); + tpsbcheck(tpcb, 1); + /* + * If transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ + if (tpcb->tp_rttemit && SEQ_GT(tpcb, seq, tpcb->tp_rttseq)) + tp_rtt_rtv(tpcb); + /* + * If all outstanding data is acked, stop retransmit timer. + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + * OSI combines the keepalive and persistance functions. + * So, there is no persistance timer per se, to restart. + */ + if (tpcb->tp_class != TP_CLASS_0) + tpcb->tp_timer[TM_data_retrans] = + (seq == tpcb->tp_sndnew) ? 0 : tpcb->tp_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet), plus a constant + * fraction of a packet (maxseg/8) to help larger windows + * open quickly enough. + */ + { + u_int cw = tpcb->tp_cong_win, incr = tpcb->tp_l_tpdusize; + + incr = min(incr, bytes_acked); + if (cw > tpcb->tp_ssthresh) + incr = incr * incr / cw + incr / 8; + tpcb->tp_cong_win = + min(cw + incr, tpcb->tp_sock->so_snd.sb_hiwat); + } + tpcb->tp_snduna = seq; + if (SEQ_LT(tpcb, tpcb->tp_sndnxt, seq)) { + tpcb->tp_sndnxt = seq; + tpcb->tp_sndnxt_m = 0; + } + bang++; + } + + if( cdt != 0 && old_fcredit == 0 ) { + tpcb->tp_sendfcc = 1; + } + if (cdt == 0) { + if (old_fcredit != 0) + IncStat(ts_zfcdt); + /* The following might mean that the window shrunk */ + if (tpcb->tp_timer[TM_data_retrans]) { + tpcb->tp_timer[TM_data_retrans] = 0; + tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; + if (tpcb->tp_sndnxt != tpcb->tp_snduna) { + tpcb->tp_sndnxt = tpcb->tp_snduna; + tpcb->tp_sndnxt_m = 0; + } + } + } + tpcb->tp_fcredit = cdt; + bang |= (old_fcredit < cdt); + +done: + IFDEBUG(D_ACKRECV) + printf("goodack returns 0x%x, cdt 0x%x ocdt 0x%x cwin 0x%x\n", + bang, cdt, old_fcredit, tpcb->tp_cong_win); + ENDDEBUG + /* if (bang) XXXXX Very bad to remove this test, but somethings broken */ + tp_send(tpcb); + return (bang); +} + +/* + * CALLED FROM: + * tp_goodack() + * FUNCTION and ARGUMENTS: + * drops everything up TO but not INCLUDING seq # (seq) + * from the retransmission queue. + */ +tp_sbdrop(tpcb, seq) + register struct tp_pcb *tpcb; + SeqNum seq; +{ + struct sockbuf *sb = &tpcb->tp_sock->so_snd; + register int i = SEQ_SUB(tpcb, seq, tpcb->tp_snduna); + int oldcc = sb->sb_cc, oldi = i; + + if (i >= tpcb->tp_seqhalf) + printf("tp_spdropping too much -- should panic"); + while (i-- > 0) + sbdroprecord(sb); + IFDEBUG(D_ACKRECV) + printf("tp_sbdroping %d pkts %d bytes on %x at 0x%x\n", + oldi, oldcc - sb->sb_cc, tpcb, seq); + ENDDEBUG + if (sb->sb_flags & SB_NOTIFY) + sowwakeup(tpcb->tp_sock); + return (oldcc - sb->sb_cc); +} + +/* + * CALLED FROM: + * tp.trans on user send request, arrival of AK and arrival of XAK + * FUNCTION and ARGUMENTS: + * Emits tpdus starting at sequence number (tpcb->tp_sndnxt). + * Emits until a) runs out of data, or b) runs into an XPD mark, or + * c) it hits seq number (highseq) limited by cong or credit. + * + * If you want XPD to buffer > 1 du per socket buffer, you can + * modifiy this to issue XPD tpdus also, but then it'll have + * to take some argument(s) to distinguish between the type of DU to + * hand tp_emit. + * + * When something is sent for the first time, its time-of-send + * is stashed (in system clock ticks rather than pf_slowtimo ticks). + * When the ack arrives, the smoothed round-trip time is figured + * using this value. + */ +void +tp_send(tpcb) + register struct tp_pcb *tpcb; +{ + register int len; + register struct mbuf *m; + struct mbuf *mb = 0; + struct sockbuf *sb = &tpcb->tp_sock->so_snd; + unsigned int eotsdu = 0; + SeqNum highseq, checkseq; + int idle, idleticks, off, cong_win; +#ifdef TP_PERF_MEAS + int send_start_time = ticks; + SeqNum oldnxt = tpcb->tp_sndnxt; +#endif /* TP_PERF_MEAS */ + + idle = (tpcb->tp_snduna == tpcb->tp_sndnew); + if (idle) { + idleticks = tpcb->tp_inact_ticks - tpcb->tp_timer[TM_inact]; + if (idleticks > tpcb->tp_dt_ticks) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; + } + + cong_win = tpcb->tp_cong_win; + highseq = SEQ(tpcb, tpcb->tp_fcredit + tpcb->tp_snduna); + if (tpcb->tp_Xsnd.sb_mb) + highseq = SEQ_MIN(tpcb, highseq, tpcb->tp_sndnew); + + IFDEBUG(D_DATA) + printf("tp_send enter tpcb 0x%x nxt 0x%x win %d high 0x%x\n", + tpcb, tpcb->tp_sndnxt, cong_win, highseq); + ENDDEBUG + IFTRACE(D_DATA) + tptraceTPCB( TPPTmisc, "tp_send sndnew snduna", + tpcb->tp_sndnew, tpcb->tp_snduna, 0, 0); + tptraceTPCB( TPPTmisc, "tp_send tpcb->tp_sndnxt win fcredit congwin", + tpcb->tp_sndnxt, cong_win, tpcb->tp_fcredit, tpcb->tp_cong_win); + ENDTRACE + IFTRACE(D_DATA) + tptraceTPCB( TPPTmisc, "tp_send 2 nxt high fcredit congwin", + tpcb->tp_sndnxt, highseq, tpcb->tp_fcredit, cong_win); + ENDTRACE + + if (tpcb->tp_sndnxt_m) + m = tpcb->tp_sndnxt_m; + else { + off = SEQ_SUB(tpcb, tpcb->tp_sndnxt, tpcb->tp_snduna); + for (m = sb->sb_mb; m && off > 0; m = m->m_next) + off--; + } +send: + /* + * Avoid silly window syndrome here . . . figure out how! + */ + checkseq = tpcb->tp_sndnum; + if (idle && SEQ_LT(tpcb, tpcb->tp_sndnum, highseq)) + checkseq = highseq; /* i.e. DON'T retain highest assigned packet */ + + while ((SEQ_LT(tpcb, tpcb->tp_sndnxt, highseq)) && m && cong_win > 0) { + + eotsdu = (m->m_flags & M_EOR) != 0; + len = m->m_pkthdr.len; + if (tpcb->tp_sndnxt == checkseq && eotsdu == 0 && + len < (tpcb->tp_l_tpdusize / 2)) + break; /* Nagle . . . . . */ + cong_win -= len; + /* make a copy - mb goes into the retransmission list + * while m gets emitted. m_copy won't copy a zero-length mbuf. + */ + mb = m; + m = m_copy(mb, 0, M_COPYALL); + if (m == MNULL) + break; + IFTRACE(D_STASH) + tptraceTPCB( TPPTmisc, + "tp_send mcopy nxt high eotsdu len", + tpcb->tp_sndnxt, highseq, eotsdu, len); + ENDTRACE + + IFDEBUG(D_DATA) + printf("tp_sending tpcb 0x%x nxt 0x%x\n", + tpcb, tpcb->tp_sndnxt); + ENDDEBUG + /* when headers are precomputed, may need to fill + in checksum here */ + if (tpcb->tp_sock->so_error = + tp_emit(DT_TPDU_type, tpcb, tpcb->tp_sndnxt, eotsdu, m)) { + /* error */ + break; + } + m = mb->m_nextpkt; + tpcb->tp_sndnxt_m = m; + if (tpcb->tp_sndnxt == tpcb->tp_sndnew) { + SEQ_INC(tpcb, tpcb->tp_sndnew); + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tpcb->tp_rttemit == 0) { + tpcb->tp_rttemit = ticks; + tpcb->tp_rttseq = tpcb->tp_sndnxt; + } + tpcb->tp_sndnxt = tpcb->tp_sndnew; + } else + SEQ_INC(tpcb, tpcb->tp_sndnxt); + /* + * Set retransmit timer if not currently set. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tpcb->tp_timer[TM_data_retrans] == 0 && + tpcb->tp_class != TP_CLASS_0) { + tpcb->tp_timer[TM_data_retrans] = tpcb->tp_dt_ticks; + tpcb->tp_timer[TM_sendack] = tpcb->tp_keepalive_ticks; + tpcb->tp_rxtshift = 0; + } + } + if (SEQ_GT(tpcb, tpcb->tp_sndnew, tpcb->tp_sndnum)) + tpcb->tp_oktonagle = 0; +#ifdef TP_PERF_MEAS + IFPERF(tpcb) + { + register int npkts; + int elapsed = ticks - send_start_time, *t; + struct timeval now; + + npkts = SEQ_SUB(tpcb, tpcb->tp_sndnxt, oldnxt); + + if (npkts > 0) + tpcb->tp_Nwindow++; + + if (npkts > TP_PM_MAX) + npkts = TP_PM_MAX; + + t = &(tpcb->tp_p_meas->tps_sendtime[npkts]); + *t += (t - elapsed) >> TP_RTT_ALPHA; + + if (mb == 0) { + IncPStat(tpcb, tps_win_lim_by_data[npkts] ); + } else { + IncPStat(tpcb, tps_win_lim_by_cdt[npkts] ); + /* not true with congestion-window being used */ + } + now.tv_sec = elapsed / hz; + now.tv_usec = (elapsed - (hz * now.tv_sec)) * 1000000 / hz; + tpmeas( tpcb->tp_lref, + TPsbsend, &elapsed, newseq, tpcb->tp_Nwindow, npkts); + } + ENDPERF +#endif /* TP_PERF_MEAS */ + + + IFTRACE(D_DATA) + tptraceTPCB( TPPTmisc, + "tp_send at end: new nxt eotsdu error", + tpcb->tp_sndnew, tpcb->tp_sndnxt, eotsdu, tpcb->tp_sock->so_error); + + ENDTRACE +} + +int TPNagleok; +int TPNagled; + +tp_packetize(tpcb, m, eotsdu) +register struct tp_pcb *tpcb; +register struct mbuf *m; +int eotsdu; +{ + register struct mbuf *n; + register struct sockbuf *sb = &tpcb->tp_sock->so_snd; + int maxsize = tpcb->tp_l_tpdusize + - tp_headersize(DT_TPDU_type, tpcb) + - (tpcb->tp_use_checksum?4:0) ; + int totlen = m->m_pkthdr.len; + struct mbuf *m_split(); + /* + * Pre-packetize the data in the sockbuf + * according to negotiated mtu. Do it here + * where we can safely wait for mbufs. + * + * This presumes knowledge of sockbuf conventions. + * TODO: allocate space for header and fill it in (once!). + */ + IFDEBUG(D_DATA) + printf("SEND BF: maxsize %d totlen %d eotsdu %d sndnum 0x%x\n", + maxsize, totlen, eotsdu, tpcb->tp_sndnum); + ENDTRACE + if (tpcb->tp_oktonagle) { + if ((n = sb->sb_mb) == 0) + panic("tp_packetize"); + while (n->m_act) + n = n->m_act; + if (n->m_flags & M_EOR) + panic("tp_packetize 2"); + SEQ_INC(tpcb, tpcb->tp_sndnum); + if (totlen + n->m_pkthdr.len < maxsize) { + /* There is an unsent packet with space, combine data */ + struct mbuf *old_n = n; + tpsbcheck(tpcb,3); + n->m_pkthdr.len += totlen; + while (n->m_next) + n = n->m_next; + sbcompress(sb, m, n); + tpsbcheck(tpcb,4); + n = old_n; + TPNagled++; + goto out; + } + } + while (m) { + n = m; + if (totlen > maxsize) { + if ((m = m_split(n, maxsize, M_WAIT)) == 0) + panic("tp_packetize"); + } else + m = 0; + totlen -= maxsize; + tpsbcheck(tpcb, 5); + sbappendrecord(sb, n); + tpsbcheck(tpcb, 6); + SEQ_INC(tpcb, tpcb->tp_sndnum); + } +out: + if (eotsdu) { + n->m_flags |= M_EOR; /* XXX belongs at end */ + tpcb->tp_oktonagle = 0; + } else { + SEQ_DEC(tpcb, tpcb->tp_sndnum); + tpcb->tp_oktonagle = 1; + TPNagleok++; + } + IFDEBUG(D_DATA) + printf("SEND out: oktonagle %d sndnum 0x%x\n", + tpcb->tp_oktonagle, tpcb->tp_sndnum); + ENDTRACE + return 0; +} + + +/* + * NAME: tp_stash() + * CALLED FROM: + * tp.trans on arrival of a DT tpdu + * FUNCTION, ARGUMENTS, and RETURN VALUE: + * Returns 1 if + * a) something new arrived and it's got eotsdu_reached bit on, + * b) this arrival was caused other out-of-sequence things to be + * accepted, or + * c) this arrival is the highest seq # for which we last gave credit + * (sender just sent a whole window) + * In other words, returns 1 if tp should send an ack immediately, 0 if + * the ack can wait a while. + * + * Note: this implementation no longer renegs on credit, (except + * when debugging option D_RENEG is on, for the purpose of testing + * ack subsequencing), so we don't need to check for incoming tpdus + * being in a reneged portion of the window. + */ + +tp_stash(tpcb, e) + register struct tp_pcb *tpcb; + register struct tp_event *e; +{ + register int ack_reason= tpcb->tp_ack_strat & ACK_STRAT_EACH; + /* 0--> delay acks until full window */ + /* 1--> ack each tpdu */ +#ifndef lint +#define E e->ATTR(DT_TPDU) +#else /* lint */ +#define E e->ev_union.EV_DT_TPDU +#endif /* lint */ + + if ( E.e_eot ) { + register struct mbuf *n = E.e_data; + n->m_flags |= M_EOR; + n->m_act = 0; + } + IFDEBUG(D_STASH) + dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, + "stash: so_rcv before appending"); + dump_mbuf(E.e_data, + "stash: e_data before appending"); + ENDDEBUG + + IFPERF(tpcb) + PStat(tpcb, Nb_from_ll) += E.e_datalen; + tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, + E.e_seq, (u_int)PStat(tpcb, Nb_from_ll), (u_int)E.e_datalen); + ENDPERF + + if (E.e_seq == tpcb->tp_rcvnxt) { + + IFDEBUG(D_STASH) + printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x\n", + E.e_seq, E.e_datalen, E.e_eot); + ENDDEBUG + + IFTRACE(D_STASH) + tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", + E.e_seq, E.e_datalen, E.e_eot, 0); + ENDTRACE + + SET_DELACK(tpcb); + + sbappend(&tpcb->tp_sock->so_rcv, E.e_data); + + SEQ_INC( tpcb, tpcb->tp_rcvnxt ); + /* + * move chains from the reassembly queue to the socket buffer + */ + if (tpcb->tp_rsycnt) { + register struct mbuf **mp; + struct mbuf **mplim; + + mp = tpcb->tp_rsyq + (tpcb->tp_rcvnxt % tpcb->tp_maxlcredit); + mplim = tpcb->tp_rsyq + tpcb->tp_maxlcredit; + + while (tpcb->tp_rsycnt && *mp) { + sbappend(&tpcb->tp_sock->so_rcv, *mp); + tpcb->tp_rsycnt--; + *mp = 0; + SEQ_INC(tpcb, tpcb->tp_rcvnxt); + ack_reason |= ACK_REORDER; + if (++mp == mplim) + mp = tpcb->tp_rsyq; + } + } + IFDEBUG(D_STASH) + dump_mbuf(tpcb->tp_sock->so_rcv.sb_mb, + "stash: so_rcv after appending"); + ENDDEBUG + + } else { + register struct mbuf **mp; + SeqNum uwe; + + IFTRACE(D_STASH) + tptraceTPCB(TPPTmisc, "stash Reseq: seq rcvnxt lcdt", + E.e_seq, tpcb->tp_rcvnxt, tpcb->tp_lcredit, 0); + ENDTRACE + + if (tpcb->tp_rsyq == 0) + tp_rsyset(tpcb); + uwe = SEQ(tpcb, tpcb->tp_rcvnxt + tpcb->tp_maxlcredit); + if (tpcb->tp_rsyq == 0 || + !IN_RWINDOW(tpcb, E.e_seq, tpcb->tp_rcvnxt, uwe)) { + ack_reason = ACK_DONT; + m_freem(E.e_data); + } else if (*(mp = tpcb->tp_rsyq + (E.e_seq % tpcb->tp_maxlcredit))) { + IFDEBUG(D_STASH) + printf("tp_stash - drop & ack\n"); + ENDDEBUG + + /* retransmission - drop it and force an ack */ + IncStat(ts_dt_dup); + IFPERF(tpcb) + IncPStat(tpcb, tps_n_ack_cuz_dup); + ENDPERF + + m_freem(E.e_data); + ack_reason |= ACK_DUP; + } else { + *mp = E.e_data; + tpcb->tp_rsycnt++; + ack_reason = ACK_DONT; + } + } + /* there were some comments of historical interest here. */ + { + LOCAL_CREDIT(tpcb); + + if ( E.e_seq == tpcb->tp_sent_uwe ) + ack_reason |= ACK_STRAT_FULLWIN; + + IFTRACE(D_STASH) + tptraceTPCB(TPPTmisc, + "end of stash, eot, ack_reason, sent_uwe ", + E.e_eot, ack_reason, tpcb->tp_sent_uwe, 0); + ENDTRACE + + if ( ack_reason == ACK_DONT ) { + IncStat( ts_ackreason[ACK_DONT] ); + return 0; + } else { + IFPERF(tpcb) + if(ack_reason & ACK_STRAT_EACH) { + IncPStat(tpcb, tps_n_ack_cuz_strat); + } else if(ack_reason & ACK_STRAT_FULLWIN) { + IncPStat(tpcb, tps_n_ack_cuz_fullwin); + } else if(ack_reason & ACK_REORDER) { + IncPStat(tpcb, tps_n_ack_cuz_reorder); + } + tpmeas(tpcb->tp_lref, TPtime_ack_sent, 0, + SEQ_ADD(tpcb, E.e_seq, 1), 0, 0); + ENDPERF + { + register int i; + + /* keep track of all reasons that apply */ + for( i=1; i<_ACK_NUM_REASONS_ ;i++) { + if( ack_reason & (1<<i) ) + IncStat( ts_ackreason[i] ); + } + } + return 1; + } + } +} + +/* + * tp_rsyflush - drop all the packets on the reassembly queue. + * Do this when closing the socket, or when somebody has changed + * the space avaible in the receive socket (XXX). + */ +tp_rsyflush(tpcb) +register struct tp_pcb *tpcb; +{ + register struct mbuf *m, **mp; + if (tpcb->tp_rsycnt) { + for (mp == tpcb->tp_rsyq + tpcb->tp_maxlcredit; + --mp >= tpcb->tp_rsyq; ) + if (*mp) { + tpcb->tp_rsycnt--; + m_freem(*mp); + } + if (tpcb->tp_rsycnt) { + printf("tp_rsyflush %x\n", tpcb); + tpcb->tp_rsycnt = 0; + } + } + free((caddr_t)tpcb->tp_rsyq, M_PCB); + tpcb->tp_rsyq = 0; +} + +tp_rsyset(tpcb) +register struct tp_pcb *tpcb; +{ + register struct socket *so = tpcb->tp_sock; + int maxcredit = tpcb->tp_xtd_format ? 0xffff : 0xf; + int old_credit = tpcb->tp_maxlcredit; + caddr_t rsyq; + + tpcb->tp_maxlcredit = maxcredit = min(maxcredit, + (so->so_rcv.sb_hiwat + tpcb->tp_l_tpdusize)/ tpcb->tp_l_tpdusize); + + if (old_credit == tpcb->tp_maxlcredit && tpcb->tp_rsyq != 0) + return; + maxcredit *= sizeof(struct mbuf *); + if (tpcb->tp_rsyq) + tp_rsyflush(tpcb); + if (rsyq = (caddr_t)malloc(maxcredit, M_PCB, M_NOWAIT)) + bzero(rsyq, maxcredit); + tpcb->tp_rsyq = (struct mbuf **)rsyq; +} + +tpsbcheck(tpcb, i) +struct tp_pcb *tpcb; +{ + register struct mbuf *n, *m; + register int len = 0, mbcnt = 0, pktlen; + struct sockbuf *sb = &tpcb->tp_sock->so_snd; + + for (n = sb->sb_mb; n; n = n->m_nextpkt) { + if ((n->m_flags & M_PKTHDR) == 0) + panic("tpsbcheck nohdr"); + pktlen = len + n->m_pkthdr.len; + for (m = n; m; m = m->m_next) { + len += m->m_len; + mbcnt += MSIZE; + if (m->m_flags & M_EXT) + mbcnt += m->m_ext.ext_size; + } + if (len != pktlen) { + printf("test %d; len %d != pktlen %d on mbuf 0x%x\n", + i, len, pktlen, n); + panic("tpsbcheck short"); + } + } + if (len != sb->sb_cc || mbcnt != sb->sb_mbcnt) { + printf("test %d: cc %d != %d || mbcnt %d != %d\n", i, len, sb->sb_cc, + mbcnt, sb->sb_mbcnt); + panic("tpsbcheck"); + } +} diff --git a/sys/netiso/tp_subr2.c b/sys/netiso/tp_subr2.c new file mode 100644 index 0000000..60c7ce2 --- /dev/null +++ b/sys/netiso/tp_subr2.c @@ -0,0 +1,880 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_subr2.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_subr2.c,v 5.5 88/11/18 17:28:55 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_subr2.c,v $ + * + * Some auxiliary routines: + * tp_protocol_error: required by xebec- called when a combo of state, + * event, predicate isn't covered for by the transition file. + * tp_indicate: gives indications(signals) to the user process + * tp_getoptions: initializes variables that are affected by the options + * chosen. + */ + +/* this def'n is to cause the expansion of this macro in the + * routine tp_local_credit : + */ +#define LOCAL_CREDIT_EXPAND + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#undef MNULL +#include <netiso/argo_debug.h> +#include <netiso/tp_param.h> +#include <netiso/tp_ip.h> +#include <netiso/iso.h> +#include <netiso/iso_errno.h> +#include <netiso/iso_pcb.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_seq.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_user.h> +#include <netiso/cons.h> + +#include <net/if.h> +#include <net/if_types.h> +#ifdef TRUE +#undef FALSE +#undef TRUE +#endif +#include <netccitt/x25.h> +#include <netccitt/pk.h> +#include <netccitt/pk_var.h> + +void tp_rsyset(); + +/* + * NAME: tp_local_credit() + * + * CALLED FROM: + * tp_emit(), tp_usrreq() + * + * FUNCTION and ARGUMENTS: + * Computes the local credit and stashes it in tpcb->tp_lcredit. + * It's a macro in the production system rather than a procdure. + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + * This doesn't actually get called in a production system - + * the macro gets expanded instead in place of calls to this proc. + * But for debugging, we call this and that allows us to add + * debugging messages easily here. + */ +void +tp_local_credit(tpcb) + struct tp_pcb *tpcb; +{ + LOCAL_CREDIT(tpcb); + IFDEBUG(D_CREDIT) + printf("ref 0x%x lcdt 0x%x l_tpdusize 0x%x decbit 0x%x\n", + tpcb->tp_lref, + tpcb->tp_lcredit, + tpcb->tp_l_tpdusize, + tpcb->tp_decbit, + tpcb->tp_cong_win + ); + ENDDEBUG + IFTRACE(D_CREDIT) + tptraceTPCB(TPPTmisc, + "lcdt tpdusz \n", + tpcb->tp_lcredit, tpcb->tp_l_tpdusize, 0, 0); + ENDTRACE +} + +/* + * NAME: tp_protocol_error() + * + * CALLED FROM: + * tp_driver(), when it doesn't know what to do with + * a combo of event, state, predicate + * + * FUNCTION and ARGUMENTS: + * print error mesg + * + * RETURN VALUE: + * EIO - always + * + * SIDE EFFECTS: + * + * NOTES: + */ +int +tp_protocol_error(e,tpcb) + struct tp_event *e; + struct tp_pcb *tpcb; +{ + printf("TP PROTOCOL ERROR! tpcb 0x%x event 0x%x, state 0x%x\n", + tpcb, e->ev_number, tpcb->tp_state); + IFTRACE(D_DRIVER) + tptraceTPCB(TPPTmisc, "PROTOCOL ERROR tpcb event state", + tpcb, e->ev_number, tpcb->tp_state, 0 ); + ENDTRACE + return EIO; /* for lack of anything better */ +} + + +/* Not used at the moment */ +ProtoHook +tp_drain() +{ + return 0; +} + + +/* + * NAME: tp_indicate() + * + * CALLED FROM: + * tp.trans when XPD arrive, when a connection is being disconnected by + * the arrival of a DR or ER, and when a connection times out. + * + * FUNCTION and ARGUMENTS: + * (ind) is the type of indication : T_DISCONNECT, T_XPD + * (error) is an E* value that will be put in the socket structure + * to be passed along to the user later. + * Gives a SIGURG to the user process or group indicated by the socket + * attached to the tpcb. + * + * RETURNS: Rien + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +tp_indicate(ind, tpcb, error) + int ind; + u_short error; + register struct tp_pcb *tpcb; +{ + register struct socket *so = tpcb->tp_sock; + IFTRACE(D_INDICATION) + tptraceTPCB(TPPTindicate, ind, *(u_short *)(tpcb->tp_lsuffix), + *(u_short *)(tpcb->tp_fsuffix), error,so->so_pgid); + ENDTRACE + IFDEBUG(D_INDICATION) + char *ls, *fs; + ls = tpcb->tp_lsuffix, + fs = tpcb->tp_fsuffix, + + printf( +"indicate 0x%x lsuf 0x%02x%02x fsuf 0x%02x%02x err 0x%x noind 0x%x ref 0x%x\n", + ind, + *ls, *(ls+1), *fs, *(fs+1), + error, /*so->so_pgrp,*/ + tpcb->tp_no_disc_indications, + tpcb->tp_lref); + ENDDEBUG + + if (ind == ER_TPDU) { + register struct mbuf *m; + struct tp_disc_reason x; + + if ((so->so_state & SS_CANTRCVMORE) == 0 && + (m = m_get(M_DONTWAIT, MT_OOBDATA)) != 0) { + + x.dr_hdr.cmsg_len = m->m_len = sizeof(x); + x.dr_hdr.cmsg_level = SOL_TRANSPORT; + x.dr_hdr.cmsg_type= TPOPT_DISC_REASON; + x.dr_reason = error; + *mtod(m, struct tp_disc_reason *) = x; + sbappendrecord(&tpcb->tp_Xrcv, m); + error = 0; + } else + error = ECONNRESET; + } + so->so_error = error; + + if (ind == T_DISCONNECT) { + if (error == 0) + so->so_error = ENOTCONN; + if ( tpcb->tp_no_disc_indications ) + return; + } + IFTRACE(D_INDICATION) + tptraceTPCB(TPPTmisc, "doing sohasoutofband(so)", so,0,0,0); + ENDTRACE + sohasoutofband(so); +} + +/* + * NAME : tp_getoptions() + * + * CALLED FROM: + * tp.trans whenever we go into OPEN state + * + * FUNCTION and ARGUMENTS: + * sets the proper flags and values in the tpcb, to control + * the appropriate actions for the given class, options, + * sequence space, etc, etc. + * + * RETURNS: Nada + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +tp_getoptions(tpcb) +struct tp_pcb *tpcb; +{ + tpcb->tp_seqmask = + tpcb->tp_xtd_format ? TP_XTD_FMT_MASK : TP_NML_FMT_MASK ; + tpcb->tp_seqbit = + tpcb->tp_xtd_format ? TP_XTD_FMT_BIT : TP_NML_FMT_BIT ; + tpcb->tp_seqhalf = tpcb->tp_seqbit >> 1; + tpcb->tp_dt_ticks = + max(tpcb->tp_dt_ticks, (tpcb->tp_peer_acktime + 2)); + tp_rsyset(tpcb); + +} + +/* + * NAME: tp_recycle_tsuffix() + * + * CALLED FROM: + * Called when a ref is frozen. + * + * FUNCTION and ARGUMENTS: + * allows the suffix to be reused. + * + * RETURNS: zilch + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +tp_recycle_tsuffix(tpcb) + struct tp_pcb *tpcb; +{ + bzero((caddr_t)tpcb->tp_lsuffix, sizeof( tpcb->tp_lsuffix)); + bzero((caddr_t)tpcb->tp_fsuffix, sizeof( tpcb->tp_fsuffix)); + tpcb->tp_fsuffixlen = tpcb->tp_lsuffixlen = 0; + + (tpcb->tp_nlproto->nlp_recycle_suffix)(tpcb->tp_npcb); +} + +/* + * NAME: tp_quench() + * + * CALLED FROM: + * tp{af}_quench() when ICMP source quench or similar thing arrives. + * + * FUNCTION and ARGUMENTS: + * Drop the congestion window back to 1. + * Congestion window scheme: + * Initial value is 1. ("slow start" as Nagle, et. al. call it) + * For each good ack that arrives, the congestion window is increased + * by 1 (up to max size of logical infinity, which is to say, + * it doesn't wrap around). + * Source quench causes it to drop back to 1. + * tp_send() uses the smaller of (regular window, congestion window). + * One retransmission strategy option is to have any retransmission + * cause reset the congestion window back to 1. + * + * (cmd) is either PRC_QUENCH: source quench, or + * PRC_QUENCH2: dest. quench (dec bit) + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + */ +void +tp_quench( tpcb, cmd ) + struct tp_pcb *tpcb; + int cmd; +{ + IFDEBUG(D_QUENCH) + printf("tp_quench tpcb 0x%x ref 0x%x sufx 0x%x\n", + tpcb, tpcb->tp_lref, *(u_short *)(tpcb->tp_lsuffix)); + printf("cong_win 0x%x decbit 0x%x \n", + tpcb->tp_cong_win, tpcb->tp_decbit); + ENDDEBUG + switch(cmd) { + case PRC_QUENCH: + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; + IncStat(ts_quench); + break; + case PRC_QUENCH2: + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* might as well quench source also */ + tpcb->tp_decbit = TP_DECBIT_CLEAR_COUNT; + IncStat(ts_rcvdecbit); + break; + } +} + + +/* + * NAME: tp_netcmd() + * + * CALLED FROM: + * + * FUNCTION and ARGUMENTS: + * + * RETURNS: + * + * SIDE EFFECTS: + * + * NOTES: + */ +tp_netcmd( tpcb, cmd ) + struct tp_pcb *tpcb; + int cmd; +{ +#ifdef TPCONS + struct isopcb *isop; + struct pklcd *lcp; + + if (tpcb->tp_netservice != ISO_CONS) + return; + isop = (struct isopcb *)tpcb->tp_npcb; + lcp = (struct pklcd *)isop->isop_chan; + switch (cmd) { + + case CONN_CLOSE: + case CONN_REFUSE: + if (isop->isop_refcnt == 1) { + /* This is really superfluous, since it would happen + anyway in iso_pcbdetach, although it is a courtesy + to free up the x.25 channel before the refwait timer + expires. */ + lcp->lcd_upper = 0; + lcp->lcd_upnext = 0; + pk_disconnect(lcp); + isop->isop_chan = 0; + isop->isop_refcnt = 0; + } + break; + + default: + printf("tp_netcmd(0x%x, 0x%x) NOT IMPLEMENTED\n", tpcb, cmd); + break; + } +#else /* TPCONS */ + printf("tp_netcmd(): X25 NOT CONFIGURED!!\n"); +#endif +} +/* + * CALLED FROM: + * tp_ctloutput() and tp_emit() + * FUNCTION and ARGUMENTS: + * Convert a class mask to the highest numeric value it represents. + */ + +int +tp_mask_to_num(x) + u_char x; +{ + register int j; + + for(j = 4; j>=0 ;j--) { + if(x & (1<<j)) + break; + } + ASSERT( (j == 4) || (j == 0) ); /* for now */ + if( (j != 4) && (j != 0) ) { + printf("ASSERTION ERROR: tp_mask_to_num: x 0x%x j %d\n", + x, j); + } + IFTRACE(D_TPINPUT) + tptrace(TPPTmisc, "tp_mask_to_num(x) returns j", x, j, 0, 0); + ENDTRACE + IFDEBUG(D_TPINPUT) + printf("tp_mask_to_num(0x%x) returns 0x%x\n", x, j); + ENDDEBUG + return j; +} + +static +copyQOSparms(src, dst) + struct tp_conn_param *src, *dst; +{ + /* copy all but the bits stuff at the end */ +#define COPYSIZE (12 * sizeof(short)) + + bcopy((caddr_t)src, (caddr_t)dst, COPYSIZE); + dst->p_tpdusize = src->p_tpdusize; + dst->p_ack_strat = src->p_ack_strat; + dst->p_rx_strat = src->p_rx_strat; +#undef COPYSIZE +} +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ +void +tp_mss(tpcb, nhdr_size) + register struct tp_pcb *tpcb; + int nhdr_size; +{ + register struct rtentry *rt; + struct ifnet *ifp; + register int rtt, mss; + u_long bufsize; + int i, ssthresh = 0, rt_mss; + struct socket *so; + + if (tpcb->tp_ptpdusize) + mss = tpcb->tp_ptpdusize << 7; + else + mss = 1 << tpcb->tp_tpdusize; + so = tpcb->tp_sock; + if ((rt = *(tpcb->tp_routep)) == 0) { + bufsize = so->so_rcv.sb_hiwat; + goto punt_route; + } + ifp = rt->rt_ifp; + +#ifdef RTV_MTU /* if route characteristics exist ... */ + /* + * While we're here, check if there's an initial rtt + * or rttvar. Convert from the route-table units + * to hz ticks for the smoothed timers and slow-timeout units + * for other inital variables. + */ + if (tpcb->tp_rtt == 0 && (rtt = rt->rt_rmx.rmx_rtt)) { + tpcb->tp_rtt = rtt * hz / RTM_RTTUNIT; + if (rt->rt_rmx.rmx_rttvar) + tpcb->tp_rtv = rt->rt_rmx.rmx_rttvar + * hz / RTM_RTTUNIT; + else + tpcb->tp_rtv = tpcb->tp_rtt; + } + /* + * if there's an mtu associated with the route, use it + */ + if (rt->rt_rmx.rmx_mtu) + rt_mss = rt->rt_rmx.rmx_mtu - nhdr_size; + else +#endif /* RTV_MTU */ + rt_mss = (ifp->if_mtu - nhdr_size); + if (tpcb->tp_ptpdusize == 0 || /* assume application doesn't care */ + mss > rt_mss /* network won't support what was asked for */) + mss = rt_mss; + /* can propose mtu which are multiples of 128 */ + mss &= ~0x7f; + /* + * If there's a pipesize, change the socket buffer + * to that size. + */ +#ifdef RTV_SPIPE + if ((bufsize = rt->rt_rmx.rmx_sendpipe) > 0) { +#endif + bufsize = min(bufsize, so->so_snd.sb_hiwat); + (void) sbreserve(&so->so_snd, bufsize); + } +#ifdef RTV_SPIPE + if ((bufsize = rt->rt_rmx.rmx_recvpipe) > 0) { +#endif + bufsize = min(bufsize, so->so_rcv.sb_hiwat); + (void) sbreserve(&so->so_rcv, bufsize); + } else + bufsize = so->so_rcv.sb_hiwat; +#ifdef RTV_SSTHRESH + /* + * There's some sort of gateway or interface + * buffer limit on the path. Use this to set + * the slow start threshhold, but set the + * threshold to no less than 2*mss. + */ + ssthresh = rt->rt_rmx.rmx_ssthresh; +punt_route: + /* + * The current mss is initialized to the default value. + * If we compute a smaller value, reduce the current mss. + * If we compute a larger value, return it for use in sending + * a max seg size option. + * If we received an offer, don't exceed it. + * However, do not accept offers under 128 bytes. + */ + if (tpcb->tp_l_tpdusize) + mss = min(mss, tpcb->tp_l_tpdusize); + /* + * We want a minimum recv window of 4 packets to + * signal packet loss by duplicate acks. + */ + mss = min(mss, bufsize >> 2) & ~0x7f; + mss = max(mss, 128); /* sanity */ + tpcb->tp_cong_win = + (rt == 0 || (rt->rt_flags & RTF_GATEWAY)) ? mss : bufsize; + tpcb->tp_l_tpdusize = mss; + tp_rsyset(tpcb); + tpcb->tp_ssthresh = max(2 * mss, ssthresh); + /* Calculate log2 of mss */ + for (i = TP_MIN_TPDUSIZE + 1; i <= TP_MAX_TPDUSIZE; i++) + if ((1 << i) > mss) + break; + i--; + tpcb->tp_tpdusize = i; +#endif /* RTV_MTU */ +} + +/* + * CALLED FROM: + * tp_usrreq on PRU_CONNECT and tp_input on receipt of CR + * + * FUNCTION and ARGUMENTS: + * -- An mbuf containing the peer's network address. + * -- Our control block, which will be modified + * -- In the case of cons, a control block for that layer. + * + * + * RETURNS: + * errno value : + * EAFNOSUPPORT if can't find an nl_protosw for x.25 (really could panic) + * ECONNREFUSED if trying to run TP0 with non-type 37 address + * possibly other E* returned from cons_netcmd() + * + * SIDE EFFECTS: + * Determines recommended tpdusize, buffering and intial delays + * based on information cached on the route. + */ +int +tp_route_to( m, tpcb, channel) + struct mbuf *m; + register struct tp_pcb *tpcb; + caddr_t channel; +{ + register struct sockaddr_iso *siso; /* NOTE: this may be a sockaddr_in */ + extern struct tp_conn_param tp_conn_param[]; + int error = 0, save_netservice = tpcb->tp_netservice; + register struct rtentry *rt = 0; + int nhdr_size, mtu, bufsize; + + siso = mtod(m, struct sockaddr_iso *); + IFTRACE(D_CONN) + tptraceTPCB(TPPTmisc, + "route_to: so afi netservice class", + tpcb->tp_sock, siso->siso_addr.isoa_genaddr[0], tpcb->tp_netservice, + tpcb->tp_class); + ENDTRACE + IFDEBUG(D_CONN) + printf("tp_route_to( m x%x, channel 0x%x, tpcb 0x%x netserv 0x%x)\n", + m, channel, tpcb, tpcb->tp_netservice); + printf("m->mlen x%x, m->m_data:\n", m->m_len); + dump_buf(mtod(m, caddr_t), m->m_len); + ENDDEBUG + if (channel) { +#ifdef TPCONS + struct pklcd *lcp = (struct pklcd *)channel; + struct isopcb *isop = (struct isopcb *)lcp->lcd_upnext, + *isop_new = (struct isopcb *)tpcb->tp_npcb; + /* The next 2 lines believe that you haven't + set any network level options or done a pcbconnect + and XXXXXXX'edly apply to both inpcb's and isopcb's */ + remque(isop_new); + free(isop_new, M_PCB); + tpcb->tp_npcb = (caddr_t)isop; + tpcb->tp_netservice = ISO_CONS; + tpcb->tp_nlproto = nl_protosw + ISO_CONS; + if (isop->isop_refcnt++ == 0) { + iso_putsufx(isop, tpcb->tp_lsuffix, tpcb->tp_lsuffixlen, TP_LOCAL); + isop->isop_socket = tpcb->tp_sock; + } else + /* there are already connections sharing this */; +#endif + } else { + switch (siso->siso_family) { + default: + error = EAFNOSUPPORT; + goto done; +#ifdef ISO + case AF_ISO: + { + struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + int flags = tpcb->tp_sock->so_options & SO_DONTROUTE; + tpcb->tp_netservice = ISO_CLNS; + if (clnp_route(&siso->siso_addr, &isop->isop_route, + flags, (void **)0, (void **)0) == 0) { + rt = isop->isop_route.ro_rt; + if (rt && rt->rt_flags & RTF_PROTO1) + tpcb->tp_netservice = ISO_CONS; + } + } break; +#endif +#ifdef INET + case AF_INET: + tpcb->tp_netservice = IN_CLNS; +#endif + } + if (tpcb->tp_nlproto->nlp_afamily != siso->siso_family) { + IFDEBUG(D_CONN) + printf("tp_route_to( CHANGING nlproto old 0x%x new 0x%x)\n", + save_netservice, tpcb->tp_netservice); + ENDDEBUG + if (error = tp_set_npcb(tpcb)) + goto done; + } + IFDEBUG(D_CONN) + printf("tp_route_to calling nlp_pcbconn, netserv %d\n", + tpcb->tp_netservice); + ENDDEBUG + tpcb->tp_nlproto = nl_protosw + tpcb->tp_netservice; + error = (tpcb->tp_nlproto->nlp_pcbconn)(tpcb->tp_npcb, m); + } + if (error) + goto done; + nhdr_size = tpcb->tp_nlproto->nlp_mtu(tpcb); /* only gets common info */ + tp_mss(tpcb, nhdr_size); +done: + IFDEBUG(D_CONN) + printf("tp_route_to returns 0x%x\n", error); + ENDDEBUG + IFTRACE(D_CONN) + tptraceTPCB(TPPTmisc, "route_to: returns: error netserv class", error, + tpcb->tp_netservice, tpcb->tp_class, 0); + ENDTRACE + return error; +} + + +/* class zero version */ +void +tp0_stash( tpcb, e ) + register struct tp_pcb *tpcb; + register struct tp_event *e; +{ +#ifndef lint +#define E e->ATTR(DT_TPDU) +#else /* lint */ +#define E e->ev_union.EV_DT_TPDU +#endif /* lint */ + + register struct sockbuf *sb = &tpcb->tp_sock->so_rcv; + register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + + IFPERF(tpcb) + PStat(tpcb, Nb_from_ll) += E.e_datalen; + tpmeas(tpcb->tp_lref, TPtime_from_ll, &e->e_time, + E.e_seq, PStat(tpcb, Nb_from_ll), E.e_datalen); + ENDPERF + + IFDEBUG(D_STASH) + printf("stash EQ: seq 0x%x datalen 0x%x eot 0x%x", + E.e_seq, E.e_datalen, E.e_eot); + ENDDEBUG + + IFTRACE(D_STASH) + tptraceTPCB(TPPTmisc, "stash EQ: seq len eot", + E.e_seq, E.e_datalen, E.e_eot, 0); + ENDTRACE + + if ( E.e_eot ) { + register struct mbuf *n = E.e_data; + n->m_flags |= M_EOR; + n->m_act = MNULL; /* set on tp_input */ + } + sbappend(sb, E.e_data); + IFDEBUG(D_STASH) + dump_mbuf(sb->sb_mb, "stash 0: so_rcv after appending"); + ENDDEBUG + if (tpcb->tp_netservice != ISO_CONS) + printf("tp0_stash: tp running over something wierd\n"); + else { + register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; + pk_flowcontrol(lcp, sbspace(sb) <= 0, 1); + } +} + +void +tp0_openflow(tpcb) +register struct tp_pcb *tpcb; +{ + register struct isopcb *isop = (struct isopcb *)tpcb->tp_npcb; + if (tpcb->tp_netservice != ISO_CONS) + printf("tp0_openflow: tp running over something wierd\n"); + else { + register struct pklcd *lcp = (struct pklcd *)isop->isop_chan; + if (lcp->lcd_rxrnr_condition) + pk_flowcontrol(lcp, 0, 0); + } +} +#ifndef TPCONS +static +pk_flowcontrol() {} +#endif + +#ifdef TP_PERF_MEAS +/* + * CALLED FROM: + * tp_ctloutput() when the user sets TPOPT_PERF_MEAS on + * and tp_newsocket() when a new connection is made from + * a listening socket with tp_perf_on == true. + * FUNCTION and ARGUMENTS: + * (tpcb) is the usual; this procedure gets a clear cluster mbuf for + * a tp_pmeas structure, and makes tpcb->tp_p_meas point to it. + * RETURN VALUE: + * ENOBUFS if it cannot get a cluster mbuf. + */ + +int +tp_setup_perf(tpcb) + register struct tp_pcb *tpcb; +{ + register struct mbuf *q; + + if( tpcb->tp_p_meas == 0 ) { + MGET(q, M_WAITOK, MT_PCB); + if (q == 0) + return ENOBUFS; + MCLGET(q, M_WAITOK); + if ((q->m_flags & M_EXT) == 0) { + (void) m_free(q); + return ENOBUFS; + } + q->m_len = sizeof (struct tp_pmeas); + tpcb->tp_p_mbuf = q; + tpcb->tp_p_meas = mtod(q, struct tp_pmeas *); + bzero( (caddr_t)tpcb->tp_p_meas, sizeof (struct tp_pmeas) ); + IFDEBUG(D_PERF_MEAS) + printf( + "tpcb 0x%x so 0x%x ref 0x%x tp_p_meas 0x%x tp_perf_on 0x%x\n", + tpcb, tpcb->tp_sock, tpcb->tp_lref, + tpcb->tp_p_meas, tpcb->tp_perf_on); + ENDDEBUG + tpcb->tp_perf_on = 1; + } + return 0; +} +#endif /* TP_PERF_MEAS */ + +#ifdef ARGO_DEBUG +dump_addr (addr) + register struct sockaddr *addr; +{ + switch( addr->sa_family ) { + case AF_INET: + dump_inaddr((struct sockaddr_in *)addr); + break; +#ifdef ISO + case AF_ISO: + dump_isoaddr((struct sockaddr_iso *)addr); + break; +#endif /* ISO */ + default: + printf("BAD AF: 0x%x\n", addr->sa_family); + break; + } +} + +#define MAX_COLUMNS 8 +/* + * Dump the buffer to the screen in a readable format. Format is: + * + * hex/dec where hex is the hex format, dec is the decimal format. + * columns of hex/dec numbers will be printed, followed by the + * character representations (if printable). + */ +Dump_buf(buf, len) +caddr_t buf; +int len; +{ + int i,j; +#define Buf ((u_char *)buf) + printf("Dump buf 0x%x len 0x%x\n", buf, len); + for (i = 0; i < len; i += MAX_COLUMNS) { + printf("+%d:\t", i); + for (j = 0; j < MAX_COLUMNS; j++) { + if (i + j < len) { + printf("%x/%d\t", Buf[i+j], Buf[i+j]); + } else { + printf(" "); + } + } + + for (j = 0; j < MAX_COLUMNS; j++) { + if (i + j < len) { + if (((Buf[i+j]) > 31) && ((Buf[i+j]) < 128)) + printf("%c", Buf[i+j]); + else + printf("."); + } + } + printf("\n"); + } +} +#endif /* ARGO_DEBUG */ diff --git a/sys/netiso/tp_timer.c b/sys/netiso/tp_timer.c new file mode 100644 index 0000000..b3a0be3 --- /dev/null +++ b/sys/netiso/tp_timer.c @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $ + * + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/malloc.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/kernel.h> + +#include <netiso/argo_debug.h> +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_seq.h> + +struct tp_ref *tp_ref; +int tp_rttdiv, tp_rttadd, N_TPREF = 127; +struct tp_refinfo tp_refinfo; +struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; + +/* + * CALLED FROM: + * at autoconfig time from tp_init() + * a combo of event, state, predicate + * FUNCTION and ARGUMENTS: + * initialize data structures for the timers + */ +void +tp_timerinit() +{ + register int s; + /* + * Initialize storage + */ + if (tp_refinfo.tpr_base) + return; + tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ + s = sizeof(*tp_ref) * tp_refinfo.tpr_size; + if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0) + panic("tp_timerinit"); + bzero((caddr_t)tp_ref, (unsigned) s); + tp_refinfo.tpr_base = tp_ref; + tp_rttdiv = hz / PR_SLOWHZ; + tp_rttadd = (2 * tp_rttdiv) - 1; +} +#ifdef TP_DEBUG_TIMERS +/********************** e timers *************************/ + +/* + * CALLED FROM: + * tp.trans all over + * FUNCTION and ARGUMENTS: + * Set an E type timer. + */ +void +tp_etimeout(tpcb, fun, ticks) + register struct tp_pcb *tpcb; + int fun; /* function to be called */ + int ticks; +{ + + register u_int *callp; + IFDEBUG(D_TIMER) + printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state); + ENDDEBUG + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref, + tpcb->tp_state, ticks, tp_stat.ts_Eticks); + ENDTRACE + if (tpcb == 0) + return; + IncStat(ts_Eset); + if (ticks == 0) + ticks = 1; + callp = tpcb->tp_timer + fun; + if (*callp == 0 || *callp > ticks) + *callp = ticks; +} + +/* + * CALLED FROM: + * tp.trans all over + * FUNCTION and ARGUMENTS: + * Cancel all occurrences of E-timer function (fun) for reference (refp) + */ +void +tp_euntimeout(tpcb, fun) + register struct tp_pcb *tpcb; + int fun; +{ + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); + ENDTRACE + + if (tpcb) + tpcb->tp_timer[fun] = 0; +} + +/**************** c timers ********************** + * + * These are not chained together; they sit + * in the tp_ref structure. they are the kind that + * are typically cancelled so it's faster not to + * mess with the chains + */ +#endif +/* + * CALLED FROM: + * the clock, every 500 ms + * FUNCTION and ARGUMENTS: + * Look for open references with active timers. + * If they exist, call the appropriate timer routines to update + * the timers and possibly generate events. + */ +ProtoHook +tp_slowtimo() +{ + register u_int *cp; + register struct tp_ref *rp; + struct tp_pcb *tpcb; + struct tp_event E; + int s = splnet(), t; + + /* check only open reference structures */ + IncStat(ts_Cticks); + /* tp_ref[0] is never used */ + for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { + if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN) + continue; + /* check the timers */ + for (t = 0; t < TM_NTIMERS; t++) { + cp = tpcb->tp_timer + t; + if (*cp && --(*cp) <= 0 ) { + *cp = 0; + E.ev_number = t; + IFDEBUG(D_TIMER) + printf("tp_slowtimo: pcb 0x%x t %d\n", + tpcb, t); + ENDDEBUG + IncStat(ts_Cexpired); + tp_driver(tpcb, &E); + if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { + if (tpcb->tp_notdetached) { + IFDEBUG(D_CONN) + printf("PRU_DETACH: not detached\n"); + ENDDEBUG + tp_detach(tpcb); + } + /* XXX wart; where else to do it? */ + free((caddr_t)tpcb, M_PCB); + } + } + } + } + splx(s); + return 0; +} + +/* + * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. + */ +tp_data_retrans(tpcb) +register struct tp_pcb *tpcb; +{ + int rexmt, win; + tpcb->tp_rttemit = 0; /* cancel current round trip time */ + tpcb->tp_dupacks = 0; + tpcb->tp_sndnxt = tpcb->tp_snduna; + if (tpcb->tp_fcredit == 0) { + /* + * We transmitted new data, started timing it and the window + * got shrunk under us. This can only happen if all data + * that they wanted us to send got acked, so don't + * bother shrinking the congestion windows, et. al. + * The retransmission timer should have been reset in goodack() + */ + IFDEBUG(D_ACKRECV) + printf("tp_data_retrans: 0 window tpcb 0x%x una 0x%x\n", + tpcb, tpcb->tp_snduna); + ENDDEBUG + tpcb->tp_rxtshift = 0; + tpcb->tp_timer[TM_data_retrans] = 0; + tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; + return; + } + rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT); + win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2)); + win = max(win, 2); + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ + tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; + /* We're losing; our srtt estimate is probably bogus. + * Clobber it so we'll take the next rtt measurement as our srtt; + * Maintain current rxt times until then. + */ + if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { + /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ + tpcb->tp_rtt = 0; + } + TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128); + tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur; + tp_send(tpcb); +} + +int +tp_fasttimo() +{ + register struct tp_pcb *t; + int s = splnet(); + struct tp_event E; + + E.ev_number = TM_sendack; + while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { + if (t == 0) { + printf("tp_fasttimeo: should panic"); + tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; + } else { + if (t->tp_flags & TPF_DELACK) { + IncStat(ts_Fdelack); + tp_driver(t, &E); + t->tp_flags &= ~TPF_DELACK; + } else + IncStat(ts_Fpruned); + tp_ftimeolist = t->tp_fasttimeo; + t->tp_fasttimeo = 0; + } + } + splx(s); +} + +#ifdef TP_DEBUG_TIMERS +/* + * CALLED FROM: + * tp.trans, tp_emit() + * FUNCTION and ARGUMENTS: + * Set a C type timer of type (which) to go off after (ticks) time. + */ +void +tp_ctimeout(tpcb, which, ticks) + register struct tp_pcb *tpcb; + int which, ticks; +{ + + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", + tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); + ENDTRACE + if(tpcb->tp_timer[which]) + IncStat(ts_Ccan_act); + IncStat(ts_Cset); + if (ticks <= 0) + ticks = 1; + tpcb->tp_timer[which] = ticks; +} + +/* + * CALLED FROM: + * tp.trans + * FUNCTION and ARGUMENTS: + * Version of tp_ctimeout that resets the C-type time if the + * parameter (ticks) is > the current value of the timer. + */ +void +tp_ctimeout_MIN(tpcb, which, ticks) + register struct tp_pcb *tpcb; + int which, ticks; +{ + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", + tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); + ENDTRACE + IncStat(ts_Cset); + if (tpcb->tp_timer[which]) { + tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]); + IncStat(ts_Ccan_act); + } else + tpcb->tp_timer[which] = ticks; +} + +/* + * CALLED FROM: + * tp.trans + * FUNCTION and ARGUMENTS: + * Cancel the (which) timer in the ref structure indicated by (refp). + */ +void +tp_cuntimeout(tpcb, which) + register struct tp_pcb *tpcb; + int which; +{ + IFDEBUG(D_TIMER) + printf("tp_cuntimeout(0x%x, %d) active %d\n", + tpcb, which, tpcb->tp_timer[which]); + ENDDEBUG + + IFTRACE(D_TIMER) + tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, + which, tpcb->tp_timer[which], 0); + ENDTRACE + + if (tpcb->tp_timer[which]) + IncStat(ts_Ccan_act); + else + IncStat(ts_Ccan_inact); + tpcb->tp_timer[which] = 0; +} +#endif diff --git a/sys/netiso/tp_timer.h b/sys/netiso/tp_timer.h new file mode 100644 index 0000000..a6f7735 --- /dev/null +++ b/sys/netiso/tp_timer.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_timer.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_timer.h,v 5.1 88/10/12 12:21:41 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_timer.h,v $ + * + * ARGO TP + * The callout structures used by the tp timers. + */ + +#ifndef __TP_TIMER__ +#define __TP_TIMER__ + +#define SET_DELACK(t) {\ + (t)->tp_flags |= TPF_DELACK; \ + if ((t)->tp_fasttimeo == 0)\ + { (t)->tp_fasttimeo = tp_ftimeolist; tp_ftimeolist = (t); } } + +#ifdef ARGO_DEBUG +#define TP_DEBUG_TIMERS +#endif + +#ifndef TP_DEBUG_TIMERS +#define tp_ctimeout(tpcb, which, timo) ((tpcb)->tp_timer[which] = (timo)) +#define tp_cuntimeout(tpcb, which) ((tpcb)->tp_timer[which] = 0) +#define tp_etimeout tp_ctimeout +#define tp_euntimeout tp_cuntimeout +#define tp_ctimeout_MIN(p, w, t) \ + { if((p)->tp_timer[w] > (t)) (p)->tp_timer[w] = (t);} +#endif /* TP_DEBUG_TIMERS */ + +#endif /* __TP_TIMER__ */ diff --git a/sys/netiso/tp_tpdu.h b/sys/netiso/tp_tpdu.h new file mode 100644 index 0000000..15f130d --- /dev/null +++ b/sys/netiso/tp_tpdu.h @@ -0,0 +1,296 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_tpdu.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_tpdu.h,v 4.4 88/07/26 16:45:40 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_tpdu.h,v $ + * + * This ghastly set of macros makes it possible to + * refer to tpdu structures without going mad. + */ + +#ifndef __TP_TPDU__ +#define __TP_TPDU__ + +#ifndef BYTE_ORDER +/* + * Definitions for byte order, + * according to byte significance from low address to high. + */ +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ + +#ifdef vax +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN /* mc68000, tahoe, most others */ +#endif +#endif /* BYTE_ORDER */ + +/* This much of a tpdu is the same for all types of tpdus (except + * DT tpdus in class 0; their exceptions are handled by the data + * structure below + */ +struct tpdu_fixed { + u_char _tpduf_li:8, /* length indicator */ +#if BYTE_ORDER == LITTLE_ENDIAN + _tpduf_cdt: 4, /* credit */ + _tpduf_type: 4; /* type of tpdu (DT, CR, etc.) */ +#endif +#if BYTE_ORDER == BIG_ENDIAN + _tpduf_type: 4, /* type of tpdu (DT, CR, etc.) */ + _tpduf_cdt: 4; /* credit */ +#endif + u_short _tpduf_dref; /* destination ref; not in DT in class 0 */ +}; + +#define tpdu_li _tpduf._tpduf_li +#define tpdu_type _tpduf._tpduf_type +#define tpdu_cdt _tpduf._tpduf_cdt +#define tpdu_dref _tpduf._tpduf_dref + +struct tp0du { + u_char _tp0_li, + _tp0_cdt_type, /* same as in tpdu_fixed */ +#if BYTE_ORDER == BIG_ENDIAN + _tp0_eot: 1, /* eot */ + _tp0_mbz: 7, /* must be zero */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + _tp0_mbz: 7, /* must be zero */ + _tp0_eot: 1, /* eot */ +#endif + _tp0_notused: 8; /* data begins on this octet */ +}; + +#define tp0du_eot _tp0_eot +#define tp0du_mbz _tp0_mbz + +/* + * This is used when the extended format seqence numbers are + * being sent and received. + */ + /* + * the seqeot field is an int that overlays the seq + * and eot fields, this allows the htonl operation + * to be applied to the entire 32 bit quantity, and + * simplifies the structure definitions. + */ +union seq_type { + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned int st_eot:1, /* end-of-tsdu */ + st_seq:31; /* 31 bit sequence number */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned int st_seq:31, /* 31 bit sequence number */ + st_eot:1; /* end-of-tsdu */ +#endif + } st; + unsigned int s_seqeot; +#define s_eot st.st_eot +#define s_seq st.st_seq +}; + +/* Then most tpdu types have a portion that is always present but + * differs among the tpdu types : + */ +union tpdu_fixed_rest { + + struct { + u_short _tpdufr_sref, /* source reference */ +#if BYTE_ORDER == BIG_ENDIAN + _tpdufr_class: 4, /* class [ ISO 8073 13.3.3.e ] */ + _tpdufr_opt: 4, /* options [ ISO 8073 13.3.3.e ] */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + _tpdufr_opt: 4, /* options [ ISO 8073 13.3.3.e ] */ + _tpdufr_class: 4, /* class [ ISO 8073 13.3.3.e ] */ +#endif + _tpdufr_xx: 8; /* unused */ + } CRCC; + +#define tpdu_CRli _tpduf._tpduf_li +#define tpdu_CRtype _tpduf._tpduf_type +#define tpdu_CRcdt _tpduf._tpduf_cdt +#define tpdu_CRdref_0 _tpduf._tpduf_dref +#define tpdu_CRsref _tpdufr.CRCC._tpdufr_sref +#define tpdu_sref _tpdufr.CRCC._tpdufr_sref +#define tpdu_CRclass _tpdufr.CRCC._tpdufr_class +#define tpdu_CRoptions _tpdufr.CRCC._tpdufr_opt + +#define tpdu_CCli _tpduf._tpduf_li +#define tpdu_CCtype _tpduf._tpduf_type +#define tpdu_CCcdt _tpduf._tpduf_cdt +#define tpdu_CCdref _tpduf._tpduf_dref +#define tpdu_CCsref _tpdufr.CRCC._tpdufr_sref +#define tpdu_CCclass _tpdufr.CRCC._tpdufr_class +#define tpdu_CCoptions _tpdufr.CRCC._tpdufr_opt + +/* OPTIONS and ADDL OPTIONS bits */ +#define TPO_USE_EFC 0x1 +#define TPO_XTD_FMT 0x2 +#define TPAO_USE_TXPD 0x1 +#define TPAO_NO_CSUM 0x2 +#define TPAO_USE_RCC 0x4 +#define TPAO_USE_NXPD 0x8 + + struct { + unsigned short _tpdufr_sref; /* source reference */ + unsigned char _tpdufr_reason; /* [ ISO 8073 13.5.3.d ] */ + } DR; +#define tpdu_DRli _tpduf._tpduf_li +#define tpdu_DRtype _tpduf._tpduf_type +#define tpdu_DRdref _tpduf._tpduf_dref +#define tpdu_DRsref _tpdufr.DR._tpdufr_sref +#define tpdu_DRreason _tpdufr.DR._tpdufr_reason + + unsigned short _tpdufr_sref; /* source reference */ + +#define tpdu_DCli _tpduf._tpduf_li +#define tpdu_DCtype _tpduf._tpduf_type +#define tpdu_DCdref _tpduf._tpduf_dref +#define tpdu_DCsref _tpdufr._tpdufr_sref + + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned char _tpdufr_eot:1, /* end-of-tsdu */ + _tpdufr_seq:7; /* 7 bit sequence number */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned char _tpdufr_seq:7, /* 7 bit sequence number */ + _tpdufr_eot:1; /* end-of-tsdu */ +#endif + }SEQEOT; + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned int _tpdufr_Xeot:1, /* end-of-tsdu */ + _tpdufr_Xseq:31; /* 31 bit sequence number */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned int _tpdufr_Xseq:31, /* 31 bit sequence number */ + _tpdufr_Xeot:1; /* end-of-tsdu */ +#endif + }SEQEOT31; + unsigned int _tpdufr_Xseqeot; +#define tpdu_seqeotX _tpdufr._tpdufr_Xseqeot + +#define tpdu_DTli _tpduf._tpduf_li +#define tpdu_DTtype _tpduf._tpduf_type +#define tpdu_DTdref _tpduf._tpduf_dref +#define tpdu_DTseq _tpdufr.SEQEOT._tpdufr_seq +#define tpdu_DTeot _tpdufr.SEQEOT._tpdufr_eot +#define tpdu_DTseqX _tpdufr.SEQEOT31._tpdufr_Xseq +#define tpdu_DTeotX _tpdufr.SEQEOT31._tpdufr_Xeot + +#define tpdu_XPDli _tpduf._tpduf_li +#define tpdu_XPDtype _tpduf._tpduf_type +#define tpdu_XPDdref _tpduf._tpduf_dref +#define tpdu_XPDseq _tpdufr.SEQEOT._tpdufr_seq +#define tpdu_XPDeot _tpdufr.SEQEOT._tpdufr_eot +#define tpdu_XPDseqX _tpdufr.SEQEOT31._tpdufr_Xseq +#define tpdu_XPDeotX _tpdufr.SEQEOT31._tpdufr_Xeot + + struct { +#if BYTE_ORDER == BIG_ENDIAN + unsigned _tpdufr_yrseq0:1, /* always zero */ + _tpdufr_yrseq:31; /* [ ISO 8073 13.9.3.d ] */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN + unsigned _tpdufr_yrseq:31, /* [ ISO 8073 13.9.3.d ] */ + _tpdufr_yrseq0:1; /* always zero */ +#endif + unsigned short _tpdufr_cdt; /* [ ISO 8073 13.9.3.b ] */ + } AK31; + +#define tpdu_AKli _tpduf._tpduf_li +#define tpdu_AKtype _tpduf._tpduf_type +#define tpdu_AKdref _tpduf._tpduf_dref +#define tpdu_AKseq _tpdufr.SEQEOT._tpdufr_seq +#define tpdu_AKseqX _tpdufr.AK31._tpdufr_yrseq +/* location of cdt depends on size of seq. numbers */ +#define tpdu_AKcdt _tpduf._tpduf_cdt +#define tpdu_AKcdtX _tpdufr.AK31._tpdufr_cdt + +#define tpdu_XAKli _tpduf._tpduf_li +#define tpdu_XAKtype _tpduf._tpduf_type +#define tpdu_XAKdref _tpduf._tpduf_dref +#define tpdu_XAKseq _tpdufr.SEQEOT._tpdufr_seq +#define tpdu_XAKseqX _tpdufr.SEQEOT31._tpdufr_Xseq + + unsigned char _tpdu_ERreason; /* [ ISO 8073 13.12.3.c ] */ + +#define tpdu_ERli _tpduf._tpduf_li +#define tpdu_ERtype _tpduf._tpduf_type +#define tpdu_ERdref _tpduf._tpduf_dref +#define tpdu_ERreason _tpdufr._tpdu_ERreason + +}; + +struct tpdu { + struct tpdu_fixed _tpduf; + union tpdu_fixed_rest _tpdufr; +}; + +#endif /* __TP_TPDU__ */ diff --git a/sys/netiso/tp_trace.c b/sys/netiso/tp_trace.c new file mode 100644 index 0000000..115597b --- /dev/null +++ b/sys/netiso/tp_trace.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_trace.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_trace.c,v 5.3 88/11/18 17:29:14 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_trace.c,v $ + * + * The whole protocol trace module. + * We keep a circular buffer of trace structures, which are big + * unions of different structures we might want to see. + * Unfortunately this gets too big pretty easily. Pcbs were removed + * from the tracing when the kernel got too big to boot. + */ + +#define TP_TRACEFILE + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_param.h> +#include <netiso/tp_ip.h> +#include <netiso/tp_pcb.h> +#include <netiso/tp_tpdu.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> + +#ifdef TPPT +static tp_seq = 0; +u_char tp_traceflags[128]; + +/* + * The argument tpcb is the obvious. + * event here is just the type of trace event - TPPTmisc, etc. + * The rest of the arguments have different uses depending + * on the type of trace event. + */ +/*ARGSUSED*/ +/*VARARGS*/ + +void +tpTrace(tpcb, event, arg, src, len, arg4, arg5) + struct tp_pcb *tpcb; + u_int event, arg; + u_int src; + u_int len; + u_int arg4; + u_int arg5; +{ + register struct tp_Trace *tp; + + tp = &tp_Trace[tp_Tracen++]; + tp_Tracen %= TPTRACEN; + + tp->tpt_event = event; + tp->tpt_tseq = tp_seq++; + tp->tpt_arg = arg; + if(tpcb) + tp->tpt_arg2 = tpcb->tp_lref; + bcopy( (caddr_t)&time, (caddr_t)&tp->tpt_time, sizeof(struct timeval) ); + + switch(event) { + + case TPPTertpdu: + bcopy((caddr_t)src, (caddr_t)&tp->tpt_ertpdu, + (unsigned)MIN((int)len, sizeof(struct tp_Trace))); + break; + + case TPPTusrreq: + case TPPTmisc: + + /* arg is a string */ + bcopy((caddr_t)arg, (caddr_t)tp->tpt_str, + (unsigned)MIN(1+strlen((caddr_t) arg), TPTRACE_STRLEN)); + tp->tpt_m2 = src; + tp->tpt_m3 = len; + tp->tpt_m4 = arg4; + tp->tpt_m1 = arg5; + break; + + case TPPTgotXack: + case TPPTXack: + case TPPTsendack: + case TPPTgotack: + case TPPTack: + case TPPTindicate: + default: + case TPPTdriver: + tp->tpt_m2 = arg; + tp->tpt_m3 = src; + tp->tpt_m4 = len; + tp->tpt_m5 = arg4; + tp->tpt_m1 = arg5; + break; + case TPPTparam: + bcopy((caddr_t)src, (caddr_t)&tp->tpt_param, sizeof(struct tp_param)); + break; + case TPPTref: + bcopy((caddr_t)src, (caddr_t)&tp->tpt_ref, sizeof(struct tp_ref)); + break; + + case TPPTtpduin: + case TPPTtpduout: + tp->tpt_arg2 = arg4; + bcopy((caddr_t)src, (caddr_t)&tp->tpt_tpdu, + (unsigned)MIN((int)len, sizeof(struct tp_Trace))); + break; + } +} +#endif /* TPPT */ diff --git a/sys/netiso/tp_trace.h b/sys/netiso/tp_trace.h new file mode 100644 index 0000000..8857305 --- /dev/null +++ b/sys/netiso/tp_trace.h @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_trace.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_trace.h,v 5.1 88/10/12 12:21:51 root Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_trace.h,v $ + * + * + * Definitions needed for the protocol trace mechanism. + */ + +#ifndef __TP_TRACE__ +#define __TP_TRACE__ + + +#define TPPTsendack 1 +#define TPPTgotack 2 +#define TPPTXack 3 +#define TPPTgotXack 4 +#define TPPTack 5 +#define TPPTindicate 6 +#define TPPTusrreq 7 +#define TPPTmisc 8 +#define TPPTpcb 9 +#define TPPTref 10 +#define TPPTtpduin 11 +#define TPPTparam 12 +#define TPPTertpdu 13 +#define TPPTdriver 14 +#define TPPTtpduout 15 + +#include <netiso/tp_pcb.h> + +/* this #if is to avoid lint */ + +#if defined(TP_TRACEFILE)||!defined(KERNEL) + +#include <netiso/tp_tpdu.h> + +#define TPTRACE_STRLEN 50 + + +/* for packet tracing */ +struct tp_timeval { + SeqNum tptv_seq; + u_int tptv_kind; + u_int tptv_window; + u_int tptv_size; +}; + +struct tp_Trace { + u_int tpt_event; + u_int tpt_arg; + u_int tpt_arg2; + int tpt_tseq; + struct timeval tpt_time; + union { + struct inpcb tpt_Inpcb; /* protocol control block */ + struct tp_ref tpt_Ref; /* ref part of pcb */ + struct tpdu tpt_Tpdu; /* header*/ + struct tp_refinfo tpt_Param; /* ?? bytes, make sure < 128??*/ + struct tp_timeval tpt_Time; + struct { + u_int tptm_2; + u_int tptm_3; + u_int tptm_4; + u_int tptm_5; + char tpt_Str[TPTRACE_STRLEN]; + u_int tptm_1; + } tptmisc; + u_char tpt_Ertpdu; /* use rest of structure */ + } tpt_stuff; +}; +#define tpt_inpcb tpt_stuff.tpt_Inpcb +#define tpt_pcb tpt_stuff.tpt_Pcb +#define tpt_ref tpt_stuff.tpt_Ref +#define tpt_tpdu tpt_stuff.tpt_Tpdu +#define tpt_param tpt_stuff.tpt_Param +#define tpt_ertpdu tpt_stuff.tpt_Ertpdu +#define tpt_str tpt_stuff.tptmisc.tpt_Str +#define tpt_m1 tpt_stuff.tptmisc.tptm_1 +#define tpt_m2 tpt_stuff.tptmisc.tptm_2 +#define tpt_m3 tpt_stuff.tptmisc.tptm_3 +#define tpt_m4 tpt_stuff.tptmisc.tptm_4 +#define tpt_m5 tpt_stuff.tptmisc.tptm_5 + +#define tpt_seq tpt_stuff.tpt_Time.tptv_seq +#define tpt_kind tpt_stuff.tpt_Time.tptv_kind +#define tpt_window tpt_stuff.tpt_Time.tptv_window +#define tpt_size tpt_stuff.tpt_Time.tptv_size + +#endif /* defined(TP_TRACEFILE)||!defined(KERNEL) */ + + +#ifdef TPPT + +#define TPTRACEN 300 + +#define tptrace(A,B,C,D,E,F) \ + tpTrace((struct tp_pcb *)0,\ + (u_int)(A),(u_int)(B),(u_int)(C),(u_int)(D),(u_int)(E),(u_int)(F)) + +#define tptraceTPCB(A,B,C,D,E,F) \ + tpTrace(tpcb,\ + (u_int)(A),(u_int)(B),(u_int)(C),(u_int)(D),(u_int)(E),(u_int)(F)) + +extern void tpTrace(); +extern struct tp_Trace tp_Trace[]; +extern u_char tp_traceflags[]; +int tp_Tracen = 0; + +#define IFTRACE(ascii)\ + if(tp_traceflags[ascii]) { +/* + * for some reason lint complains about tp_param being undefined no + * matter where or how many times I define it. + */ +#define ENDTRACE } + + +#else /* TPPT */ + +/*********************************************** + * NO TPPT TRACE STUFF + **********************************************/ +#define TPTRACEN 1 + +#define tptrace(A,B,C,D,E,F) 0 +#define tptraceTPCB(A,B,C,D,E,F) 0 + +#define IFTRACE(ascii) if (0) { +#define ENDTRACE } + +#endif /* TPPT */ + + + +#endif /* __TP_TRACE__ */ diff --git a/sys/netiso/tp_user.h b/sys/netiso/tp_user.h new file mode 100644 index 0000000..b81491b --- /dev/null +++ b/sys/netiso/tp_user.h @@ -0,0 +1,162 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_user.h 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_user.h,v 5.2 88/11/04 15:44:44 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_user.h,v $ + * + * These are the values a real-live user ;-) needs. + */ + +#ifndef _TYPES_ +#include <sys/types.h> +#endif + +#ifndef __TP_USER__ +#define __TP_USER__ + +struct tp_conn_param { + /* PER CONNECTION parameters */ + short p_Nretrans; + short p_dr_ticks; + + short p_cc_ticks; + short p_dt_ticks; + + short p_x_ticks; + short p_cr_ticks; + + short p_keepalive_ticks; + short p_sendack_ticks; + + short p_ref_ticks; + short p_inact_ticks; + + short p_ptpdusize; /* preferred tpdusize/128 */ + short p_winsize; + + u_char p_tpdusize; /* log 2 of size */ + + u_char p_ack_strat; /* see comments in tp_pcb.h */ + u_char p_rx_strat; /* see comments in tp_pcb.h */ + u_char p_class; /* class bitmask */ + u_char p_xtd_format; + u_char p_xpd_service; + u_char p_use_checksum; + u_char p_use_nxpd; /* netwk expedited data: not implemented */ + u_char p_use_rcc; /* receipt confirmation: not implemented */ + u_char p_use_efc; /* explicit flow control: not implemented */ + u_char p_no_disc_indications; /* don't deliver indic on disc */ + u_char p_dont_change_params; /* use these params as they are */ + u_char p_netservice; + u_char p_version; /* only here for checking */ +}; + +/* + * These sockopt level definitions should be considered for socket.h + */ +#define SOL_TRANSPORT 0xfffe +#define SOL_NETWORK 0xfffd + +/* get/set socket opt commands */ +#define TPACK_WINDOW 0x0 /* ack only on full window */ +#define TPACK_EACH 0x1 /* ack every packet */ + +#define TPRX_USE_CW 0x8 /* use congestion window transmit */ +#define TPRX_EACH 0x4 /* retrans each packet of a set */ +#define TPRX_FASTSTART 0x1 /* don't use slow start */ + +#define TPOPT_INTERCEPT 0x200 +#define TPOPT_FLAGS 0x300 +#define TPOPT_CONN_DATA 0x400 +#define TPOPT_DISC_DATA 0x500 +#define TPOPT_CFRM_DATA 0x600 +#define TPOPT_CDDATA_CLEAR 0x700 +#define TPOPT_MY_TSEL 0x800 +#define TPOPT_PEER_TSEL 0x900 +#define TPOPT_PERF_MEAS 0xa00 +#define TPOPT_PSTATISTICS 0xb00 +#define TPOPT_PARAMS 0xc00 /* to replace a bunch of the others */ +#define TPOPT_DISC_REASON 0xe00 + +struct tp_disc_reason { + struct cmsghdr dr_hdr; + u_int dr_reason; +}; + +/* + ***********************flags********************************** + */ + +/* read only flags */ +#define TPFLAG_NLQOS_PDN (u_char)0x01 +#define TPFLAG_PEER_ON_SAMENET (u_char)0x02 +#define TPFLAG_GENERAL_ADDR (u_char)0x04 /* bound to wildcard addr */ + + +/* + ***********************end flags****************************** + */ + + +#endif /* __TP_USER__ */ diff --git a/sys/netiso/tp_usrreq.c b/sys/netiso/tp_usrreq.c new file mode 100644 index 0000000..8060c94 --- /dev/null +++ b/sys/netiso/tp_usrreq.c @@ -0,0 +1,756 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_usrreq.c 8.1 (Berkeley) 6/10/93 + */ + +/*********************************************************** + Copyright IBM Corporation 1987 + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of IBM not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + +/* + * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison + */ +/* + * ARGO TP + * + * $Header: tp_usrreq.c,v 5.4 88/11/18 17:29:18 nhall Exp $ + * $Source: /usr/argo/sys/netiso/RCS/tp_usrreq.c,v $ + * + * tp_usrreq(), the fellow that gets called from most of the socket code. + * Pretty straighforward. + * THe only really awful stuff here is the OOB processing, which is done + * wholly here. + * tp_rcvoob() and tp_sendoob() are contained here and called by tp_usrreq(). + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/time.h> + +#include <netiso/tp_param.h> +#include <netiso/tp_timer.h> +#include <netiso/tp_stat.h> +#include <netiso/tp_seq.h> +#include <netiso/tp_ip.h> +#include <netiso/tp_pcb.h> +#include <netiso/argo_debug.h> +#include <netiso/tp_trace.h> +#include <netiso/tp_meas.h> +#include <netiso/iso.h> +#include <netiso/iso_errno.h> + +int tp_attach(), tp_driver(), tp_pcbbind(); +int TNew; +int TPNagle1, TPNagle2; +struct tp_pcb *tp_listeners, *tp_intercepts; + +#ifdef ARGO_DEBUG +/* + * CALLED FROM: + * anywhere you want to debug... + * FUNCTION and ARGUMENTS: + * print (str) followed by the control info in the mbufs of an mbuf chain (n) + */ +void +dump_mbuf(n, str) + struct mbuf *n; + char *str; +{ + struct mbuf *nextrecord; + + printf("dump %s\n", str); + + if (n == MNULL) { + printf("EMPTY:\n"); + return; + } + + while (n) { + nextrecord = n->m_act; + printf("RECORD:\n"); + while (n) { + printf("%x : Len %x Data %x A %x Nx %x Tp %x\n", + n, n->m_len, n->m_data, n->m_act, n->m_next, n->m_type); +#ifdef notdef + { + register char *p = mtod(n, char *); + register int i; + + printf("data: "); + for (i = 0; i < n->m_len; i++) { + if (i%8 == 0) + printf("\n"); + printf("0x%x ", *(p+i)); + } + printf("\n"); + } +#endif /* notdef */ + if (n->m_next == n) { + printf("LOOP!\n"); + return; + } + n = n->m_next; + } + n = nextrecord; + } + printf("\n"); +} + +#endif /* ARGO_DEBUG */ + +/* + * CALLED FROM: + * tp_usrreq(), PRU_RCVOOB + * FUNCTION and ARGUMENTS: + * Copy data from the expedited data socket buffer into + * the pre-allocated mbuf m. + * There is an isomorphism between XPD TPDUs and expedited data TSDUs. + * XPD tpdus are limited to 16 bytes of data so they fit in one mbuf. + * RETURN VALUE: + * EINVAL if debugging is on and a disaster has occurred + * ENOTCONN if the socket isn't connected + * EWOULDBLOCK if the socket is in non-blocking mode and there's no + * xpd data in the buffer + * E* whatever is returned from the fsm. + */ +tp_rcvoob(tpcb, so, m, outflags, inflags) + struct tp_pcb *tpcb; + register struct socket *so; + register struct mbuf *m; + int *outflags; + int inflags; +{ + register struct mbuf *n; + register struct sockbuf *sb = &so->so_rcv; + struct tp_event E; + int error = 0; + register struct mbuf **nn; + + IFDEBUG(D_XPD) + printf("PRU_RCVOOB, sostate 0x%x\n", so->so_state); + ENDDEBUG + + /* if you use soreceive */ + if (m == MNULL) + return ENOBUFS; + +restart: + if ((((so->so_state & SS_ISCONNECTED) == 0) + || (so->so_state & SS_ISDISCONNECTING) != 0) && + (so->so_proto->pr_flags & PR_CONNREQUIRED)) { + return ENOTCONN; + } + + /* Take the first mbuf off the chain. + * Each XPD TPDU gives you a complete TSDU so the chains don't get + * coalesced, but one TSDU may span several mbufs. + * Nevertheless, since n should have a most 16 bytes, it + * will fit into m. (size was checked in tp_input() ) + */ + + /* + * Code for excision of OOB data should be added to + * uipc_socket2.c (like sbappend). + */ + + sblock(sb, M_WAITOK); + for (nn = &sb->sb_mb; n = *nn; nn = &n->m_act) + if (n->m_type == MT_OOBDATA) + break; + + if (n == 0) { + IFDEBUG(D_XPD) + printf("RCVOOB: empty queue!\n"); + ENDDEBUG + sbunlock(sb); + if (so->so_state & SS_NBIO) { + return EWOULDBLOCK; + } + sbwait(sb); + goto restart; + } + m->m_len = 0; + + /* Assuming at most one xpd tpdu is in the buffer at once */ + while (n != MNULL) { + m->m_len += n->m_len; + bcopy(mtod(n, caddr_t), mtod(m, caddr_t), (unsigned)n->m_len); + m->m_data += n->m_len; /* so mtod() in bcopy() above gives right addr */ + n = n->m_next; + } + m->m_data = m->m_dat; + m->m_flags |= M_EOR; + + IFDEBUG(D_XPD) + printf("tp_rcvoob: xpdlen 0x%x\n", m->m_len); + dump_mbuf(so->so_rcv.sb_mb, "RCVOOB: Rcv socketbuf"); + dump_mbuf(sb->sb_mb, "RCVOOB: Xrcv socketbuf"); + ENDDEBUG + + if ((inflags & MSG_PEEK) == 0) { + n = *nn; + *nn = n->m_act; + for (; n; n = m_free(n)) + sbfree(sb, n); + } + +release: + sbunlock(sb); + + IFTRACE(D_XPD) + tptraceTPCB(TPPTmisc, "PRU_RCVOOB @ release sb_cc m_len", + tpcb->tp_Xrcv.sb_cc, m->m_len, 0, 0); + ENDTRACE + if (error == 0) + error = DoEvent(T_USR_Xrcvd); + return error; +} + +/* + * CALLED FROM: + * tp_usrreq(), PRU_SENDOOB + * FUNCTION and ARGUMENTS: + * Send what's in the mbuf chain (m) as an XPD TPDU. + * The mbuf may not contain more then 16 bytes of data. + * XPD TSDUs aren't segmented, so they translate into + * exactly one XPD TPDU, with EOT bit set. + * RETURN VALUE: + * EWOULDBLOCK if socket is in non-blocking mode and the previous + * xpd data haven't been acked yet. + * EMSGSIZE if trying to send > max-xpd bytes (16) + * ENOBUFS if ran out of mbufs + */ +tp_sendoob(tpcb, so, xdata, outflags) + struct tp_pcb *tpcb; + register struct socket *so; + register struct mbuf *xdata; + int *outflags; /* not used */ +{ + /* + * Each mbuf chain represents a sequence # in the XPD seq space. + * The first one in the queue has sequence # tp_Xuna. + * When we add to the XPD queue, we stuff a zero-length + * mbuf (mark) into the DATA queue, with its sequence number in m_next + * to be assigned to this XPD tpdu, so data xfer can stop + * when it reaches the zero-length mbuf if this XPD TPDU hasn't + * yet been acknowledged. + */ + register struct sockbuf *sb = &(tpcb->tp_Xsnd); + register struct mbuf *xmark; + register int len=0; + struct tp_event E; + + IFDEBUG(D_XPD) + printf("tp_sendoob:"); + if (xdata) + printf("xdata len 0x%x\n", xdata->m_len); + ENDDEBUG + /* DO NOT LOCK the Xsnd buffer!!!! You can have at MOST one + * socket buf locked at any time!!! (otherwise you might + * sleep() in sblock() w/ a signal pending and cause the + * system call to be aborted w/ a locked socketbuf, which + * is a problem. So the so_snd buffer lock + * (done in sosend()) serves as the lock for Xpd. + */ + if (sb->sb_mb) { /* Anything already in eXpedited data sockbuf? */ + if (so->so_state & SS_NBIO) { + return EWOULDBLOCK; + } + while (sb->sb_mb) { + sbunlock(&so->so_snd); /* already locked by sosend */ + sbwait(&so->so_snd); + sblock(&so->so_snd, M_WAITOK); /* sosend will unlock on return */ + } + } + + if (xdata == (struct mbuf *)0) { + /* empty xpd packet */ + MGETHDR(xdata, M_WAIT, MT_OOBDATA); + if (xdata == NULL) { + return ENOBUFS; + } + xdata->m_len = 0; + xdata->m_pkthdr.len = 0; + } + IFDEBUG(D_XPD) + printf("tp_sendoob 1:"); + if (xdata) + printf("xdata len 0x%x\n", xdata->m_len); + ENDDEBUG + xmark = xdata; /* temporary use of variable xmark */ + while (xmark) { + len += xmark->m_len; + xmark = xmark->m_next; + } + if (len > TP_MAX_XPD_DATA) { + return EMSGSIZE; + } + IFDEBUG(D_XPD) + printf("tp_sendoob 2:"); + if (xdata) + printf("xdata len 0x%x\n", len); + ENDDEBUG + + + IFTRACE(D_XPD) + tptraceTPCB(TPPTmisc, "XPD mark m_next ", xdata->m_next, 0, 0, 0); + ENDTRACE + + sbappendrecord(sb, xdata); + + IFDEBUG(D_XPD) + printf("tp_sendoob len 0x%x\n", len); + dump_mbuf(so->so_snd.sb_mb, "XPD request Regular sndbuf:"); + dump_mbuf(tpcb->tp_Xsnd.sb_mb, "XPD request Xsndbuf:"); + ENDDEBUG + return DoEvent(T_XPD_req); +} + +/* + * CALLED FROM: + * the socket routines + * FUNCTION and ARGUMENTS: + * Handles all "user requests" except the [gs]ockopts() requests. + * The argument (req) is the request type (PRU*), + * (m) is an mbuf chain, generally used for send and + * receive type requests only. + * (nam) is used for addresses usually, in particular for the bind request. + * + */ +/*ARGSUSED*/ +ProtoHook +tp_usrreq(so, req, m, nam, controlp) + struct socket *so; + u_int req; + struct mbuf *m, *nam, *controlp; +{ + register struct tp_pcb *tpcb = sototpcb(so); + int s = splnet(); + int error = 0; + int flags, *outflags = &flags; + u_long eotsdu = 0; + struct tp_event E; + + IFDEBUG(D_REQUEST) + printf("usrreq(0x%x,%d,0x%x,0x%x,0x%x)\n",so,req,m,nam,outflags); + if (so->so_error) + printf("WARNING!!! so->so_error is 0x%x\n", so->so_error); + ENDDEBUG + IFTRACE(D_REQUEST) + tptraceTPCB(TPPTusrreq, "req so m state [", req, so, m, + tpcb?tpcb->tp_state:0); + ENDTRACE + + if ((u_int)tpcb == 0 && req != PRU_ATTACH) { + IFTRACE(D_REQUEST) + tptraceTPCB(TPPTusrreq, "req failed NO TPCB[", 0, 0, 0, 0); + ENDTRACE + splx(s); + return ENOTCONN; + } + + switch (req) { + + case PRU_ATTACH: + if (tpcb) { + error = EISCONN; + } else if ((error = tp_attach(so, (int)nam)) == 0) + tpcb = sototpcb(so); + break; + + case PRU_ABORT: /* called from close() */ + /* called for each incoming connect queued on the + * parent (accepting) socket + */ + if (tpcb->tp_state == TP_OPEN || tpcb->tp_state == TP_CONFIRMING) { + E.ATTR(T_DISC_req).e_reason = E_TP_NO_SESSION; + error = DoEvent(T_DISC_req); /* pretend it was a close() */ + break; + } /* else DROP THROUGH */ + + case PRU_DETACH: /* called from close() */ + /* called only after disconnect was called */ + error = DoEvent(T_DETACH); + if (tpcb->tp_state == TP_CLOSED) { + if (tpcb->tp_notdetached) { + IFDEBUG(D_CONN) + printf("PRU_DETACH: not detached\n"); + ENDDEBUG + tp_detach(tpcb); + } + free((caddr_t)tpcb, M_PCB); + tpcb = 0; + } + break; + + case PRU_SHUTDOWN: + /* recv end may have been released; local credit might be zero */ + case PRU_DISCONNECT: + E.ATTR(T_DISC_req).e_reason = E_TP_NORMAL_DISC; + error = DoEvent(T_DISC_req); + break; + + case PRU_BIND: + error = tp_pcbbind(tpcb, nam); + break; + + case PRU_LISTEN: + if (tpcb->tp_state != TP_CLOSED || tpcb->tp_lsuffixlen == 0 || + tpcb->tp_next == 0) + error = EINVAL; + else { + register struct tp_pcb **tt; + remque(tpcb); + tpcb->tp_next = tpcb->tp_prev = tpcb; + for (tt = &tp_listeners; *tt; tt = &((*tt)->tp_nextlisten)) + if ((*tt)->tp_lsuffixlen) + break; + tpcb->tp_nextlisten = *tt; + *tt = tpcb; + error = DoEvent(T_LISTEN_req); + } + break; + + case PRU_CONNECT2: + error = EOPNOTSUPP; /* for unix domain sockets */ + break; + + case PRU_CONNECT: + IFTRACE(D_CONN) + tptraceTPCB(TPPTmisc, + "PRU_CONNECT: so 0x%x *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", + tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, + tpcb->tp_class); + ENDTRACE + IFDEBUG(D_CONN) + printf("PRU_CONNECT: so *SHORT_LSUFXP(tpcb) 0x%x lsuflen 0x%x, class 0x%x", + tpcb->tp_sock, *SHORT_LSUFXP(tpcb), tpcb->tp_lsuffixlen, + tpcb->tp_class); + ENDDEBUG + if (tpcb->tp_lsuffixlen == 0) { + if (error = tp_pcbbind(tpcb, MNULL)) { + IFDEBUG(D_CONN) + printf("pcbbind returns error 0x%x\n", error); + ENDDEBUG + break; + } + } + IFDEBUG(D_CONN) + printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); + dump_buf(tpcb->tp_npcb, 16); + ENDDEBUG + if (error = tp_route_to(nam, tpcb, /* channel */0)) + break; + IFDEBUG(D_CONN) + printf( + "PRU_CONNECT after tpcb 0x%x so 0x%x npcb 0x%x flags 0x%x\n", + tpcb, so, tpcb->tp_npcb, tpcb->tp_flags); + printf("isop 0x%x isop->isop_socket offset 12 :\n", tpcb->tp_npcb); + dump_buf(tpcb->tp_npcb, 16); + ENDDEBUG + if (tpcb->tp_fsuffixlen == 0) { + /* didn't set peer extended suffix */ + (tpcb->tp_nlproto->nlp_getsufx)(tpcb->tp_npcb, &tpcb->tp_fsuffixlen, + tpcb->tp_fsuffix, TP_FOREIGN); + } + if (tpcb->tp_state == TP_CLOSED) { + soisconnecting(so); + error = DoEvent(T_CONN_req); + } else { + (tpcb->tp_nlproto->nlp_pcbdisc)(tpcb->tp_npcb); + error = EISCONN; + } + IFPERF(tpcb) + u_int lsufx, fsufx; + lsufx = *(u_short *)(tpcb->tp_lsuffix); + fsufx = *(u_short *)(tpcb->tp_fsuffix); + + tpmeas(tpcb->tp_lref, + TPtime_open | (tpcb->tp_xtd_format << 4), + &time, lsufx, fsufx, tpcb->tp_fref); + ENDPERF + break; + + case PRU_ACCEPT: + (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN); + IFDEBUG(D_REQUEST) + printf("ACCEPT PEERADDDR:"); + dump_buf(mtod(nam, char *), nam->m_len); + ENDDEBUG + IFPERF(tpcb) + u_int lsufx, fsufx; + lsufx = *(u_short *)(tpcb->tp_lsuffix); + fsufx = *(u_short *)(tpcb->tp_fsuffix); + + tpmeas(tpcb->tp_lref, TPtime_open, + &time, lsufx, fsufx, tpcb->tp_fref); + ENDPERF + break; + + case PRU_RCVD: + if (so->so_state & SS_ISCONFIRMING) { + if (tpcb->tp_state == TP_CONFIRMING) + error = tp_confirm(tpcb); + break; + } + IFTRACE(D_DATA) + tptraceTPCB(TPPTmisc, + "RCVD BF: lcredit sent_lcdt cc hiwat \n", + tpcb->tp_lcredit, tpcb->tp_sent_lcdt, + so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); + LOCAL_CREDIT(tpcb); + tptraceTPCB(TPPTmisc, + "PRU_RCVD AF sbspace lcredit hiwat cc", + sbspace(&so->so_rcv), tpcb->tp_lcredit, + so->so_rcv.sb_cc, so->so_rcv.sb_hiwat); + ENDTRACE + IFDEBUG(D_REQUEST) + printf("RCVD: cc %d space %d hiwat %d\n", + so->so_rcv.sb_cc, sbspace(&so->so_rcv), + so->so_rcv.sb_hiwat); + ENDDEBUG + if (((int)nam) & MSG_OOB) + error = DoEvent(T_USR_Xrcvd); + else + error = DoEvent(T_USR_rcvd); + break; + + case PRU_RCVOOB: + if ((so->so_state & SS_ISCONNECTED) == 0) { + error = ENOTCONN; + break; + } + if (! tpcb->tp_xpd_service) { + error = EOPNOTSUPP; + break; + } + /* kludge - nam is really flags here */ + error = tp_rcvoob(tpcb, so, m, outflags, (int)nam); + break; + + case PRU_SEND: + case PRU_SENDOOB: + if (controlp) { + error = tp_snd_control(controlp, so, &m); + controlp = NULL; + if (error) + break; + } + if ((so->so_state & SS_ISCONFIRMING) && + (tpcb->tp_state == TP_CONFIRMING) && + (error = tp_confirm(tpcb))) + break; + if (req == PRU_SENDOOB) { + error = (tpcb->tp_xpd_service == 0) ? + EOPNOTSUPP : tp_sendoob(tpcb, so, m, outflags); + break; + } + if (m == 0) + break; + if (m->m_flags & M_EOR) { + eotsdu = 1; + m->m_flags &= ~M_EOR; + } + if (eotsdu == 0 && m->m_pkthdr.len == 0) + break; + if (tpcb->tp_state != TP_AKWAIT && tpcb->tp_state != TP_OPEN) { + error = ENOTCONN; + break; + } + /* + * The protocol machine copies mbuf chains, + * prepends headers, assigns seq numbers, and + * puts the packets on the device. + * When they are acked they are removed from the socket buf. + * + * sosend calls this up until sbspace goes negative. + * Sbspace may be made negative by appending this mbuf chain, + * possibly by a whole cluster. + */ + { + /* + * Could have eotsdu and no data.(presently MUST have + * an mbuf though, even if its length == 0) + */ + int totlen = m->m_pkthdr.len; + struct sockbuf *sb = &so->so_snd; + IFPERF(tpcb) + PStat(tpcb, Nb_from_sess) += totlen; + tpmeas(tpcb->tp_lref, TPtime_from_session, 0, 0, + PStat(tpcb, Nb_from_sess), totlen); + ENDPERF + IFDEBUG(D_SYSCALL) + printf( + "PRU_SEND: eot %d before sbappend 0x%x len 0x%x to sb @ 0x%x\n", + eotsdu, m, totlen, sb); + dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); + dump_mbuf(m, "m : to be added"); + ENDDEBUG + tp_packetize(tpcb, m, eotsdu); + IFDEBUG(D_SYSCALL) + printf("PRU_SEND: eot %d after sbappend 0x%x\n", eotsdu, m); + dump_mbuf(sb->sb_mb, "so_snd.sb_mb"); + ENDDEBUG + if (tpcb->tp_state == TP_OPEN) + error = DoEvent(T_DATA_req); + IFDEBUG(D_SYSCALL) + printf("PRU_SEND: after driver error 0x%x \n",error); + printf("so_snd 0x%x cc 0t%d mbcnt 0t%d\n", + sb, sb->sb_cc, sb->sb_mbcnt); + dump_mbuf(sb->sb_mb, "so_snd.sb_mb after driver"); + ENDDEBUG + } + break; + + case PRU_SOCKADDR: + (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_LOCAL); + break; + + case PRU_PEERADDR: + (tpcb->tp_nlproto->nlp_getnetaddr)(tpcb->tp_npcb, nam, TP_FOREIGN); + break; + + case PRU_CONTROL: + error = EOPNOTSUPP; + break; + + case PRU_PROTOSEND: + case PRU_PROTORCV: + case PRU_SENSE: + case PRU_SLOWTIMO: + case PRU_FASTTIMO: + error = EOPNOTSUPP; + break; + + default: +#ifdef ARGO_DEBUG + printf("tp_usrreq UNKNOWN PRU %d\n", req); +#endif /* ARGO_DEBUG */ + error = EOPNOTSUPP; + } + + IFDEBUG(D_REQUEST) + printf("%s, so 0x%x, tpcb 0x%x, error %d, state %d\n", + "returning from tp_usrreq", so, tpcb, error, + tpcb ? tpcb->tp_state : 0); + ENDDEBUG + IFTRACE(D_REQUEST) + tptraceTPCB(TPPTusrreq, "END req so m state [", req, so, m, + tpcb ? tpcb->tp_state : 0); + ENDTRACE + if (controlp) { + m_freem(controlp); + printf("control data unexpectedly retained in tp_usrreq()"); + } + splx(s); + return error; +} +tp_ltrace(so, uio) +struct socket *so; +struct uio *uio; +{ + IFTRACE(D_DATA) + register struct tp_pcb *tpcb = sototpcb(so); + if (tpcb) { + tptraceTPCB(TPPTmisc, "sosend so resid iovcnt", so, + uio->uio_resid, uio->uio_iovcnt, 0); + } + ENDTRACE +} + +tp_confirm(tpcb) +register struct tp_pcb *tpcb; +{ + struct tp_event E; + if (tpcb->tp_state == TP_CONFIRMING) + return DoEvent(T_ACPT_req); + printf("Tp confirm called when not confirming; tpcb 0x%x, state 0x%x\n", + tpcb, tpcb->tp_state); + return 0; +} + +/* + * Process control data sent with sendmsg() + */ +tp_snd_control(m, so, data) + struct mbuf *m; + struct socket *so; + register struct mbuf **data; +{ + register struct cmsghdr *ch; + int error = 0; + + if (m && m->m_len) { + ch = mtod(m, struct cmsghdr *); + m->m_len -= sizeof (*ch); + m->m_data += sizeof (*ch); + error = tp_ctloutput(PRCO_SETOPT, + so, ch->cmsg_level, ch->cmsg_type, &m); + if (ch->cmsg_type == TPOPT_DISC_DATA) { + if (data && *data) { + m_freem(*data); + *data = 0; + } + error = tp_usrreq(so, PRU_DISCONNECT, (struct mbuf *)0, + (caddr_t)0, (struct mbuf *)0); + } + } + if (m) + m_freem(m); + return error; +} diff --git a/sys/netiso/tuba_subr.c b/sys/netiso/tuba_subr.c new file mode 100644 index 0000000..d346927 --- /dev/null +++ b/sys/netiso/tuba_subr.c @@ -0,0 +1,348 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tuba_subr.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> + +#include <net/route.h> +#include <net/if.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/ip_icmp.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_debug.h> + +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> +#include <netiso/tuba_table.h> + +static struct sockaddr_iso null_siso = { sizeof(null_siso), AF_ISO, }; +extern int tuba_table_size, tcp_keepidle, tcp_keepintvl, tcp_maxidle; +extern int tcppcbcachemiss, tcppredack, tcppreddat, tcprexmtthresh; +extern struct tcpiphdr tcp_saveti; +struct inpcb tuba_inpcb; +struct inpcb *tuba_last_inpcb = &tuba_inpcb; +struct isopcb tuba_isopcb; +/* + * Tuba initialization + */ +tuba_init() +{ +#define TUBAHDRSIZE (3 /*LLC*/ + 9 /*CLNP Fixed*/ + 42 /*Addresses*/ \ + + 6 /*CLNP Segment*/ + 20 /*TCP*/) + + tuba_inpcb.inp_next = tuba_inpcb.inp_prev = &tuba_inpcb; + tuba_isopcb.isop_next = tuba_isopcb.isop_prev = &tuba_isopcb; + tuba_isopcb.isop_faddr = &tuba_isopcb.isop_sfaddr; + tuba_isopcb.isop_laddr = &tuba_isopcb.isop_sladdr; + if (max_protohdr < TUBAHDRSIZE) + max_protohdr = TUBAHDRSIZE; + if (max_linkhdr + TUBAHDRSIZE > MHLEN) + panic("tuba_init"); +} + +struct addr_arg { + int error; + int offset; + u_long sum; +}; + +/* + * Calculate contribution to fudge factor for TCP checksum, + * and coincidentally set pointer for convenience of clnp_output + * if we are are responding when there is no isopcb around. + */ +static void +tuba_getaddr(arg, siso, index) + register struct addr_arg *arg; + struct sockaddr_iso **siso; + u_long index; +{ + register struct tuba_cache *tc; + if (index <= tuba_table_size && (tc = tuba_table[index])) { + if (siso) + *siso = &tc->tc_siso; + arg->sum += (arg->offset & 1 ? tc->tc_ssum : tc->tc_sum) + + (0xffff ^ index); + arg->offset += tc->tc_siso.siso_nlen + 1; + } else + arg->error = 1; +} + +tuba_output(m, tp) + register struct mbuf *m; + struct tcpcb *tp; +{ + register struct tcpiphdr *n; + struct isopcb *isop; + struct addr_arg arg; + + if (tp == 0 || (n = tp->t_template) == 0 || + (isop = (struct isopcb *)tp->t_tuba_pcb) == 0) { + isop = &tuba_isopcb; + n = mtod(m, struct tcpiphdr *); + arg.error = arg.sum = arg.offset = 0; + tuba_getaddr(&arg, &tuba_isopcb.isop_faddr, n->ti_dst.s_addr); + tuba_getaddr(&arg, &tuba_isopcb.isop_laddr, n->ti_src.s_addr); + REDUCE(arg.sum, arg.sum); + goto adjust; + } + if (n->ti_sum == 0) { + arg.error = arg.sum = arg.offset = 0; + tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_dst.s_addr); + tuba_getaddr(&arg, (struct sockaddr_iso **)0, n->ti_src.s_addr); + REDUCE(arg.sum, arg.sum); + n->ti_sum = arg.sum; + n = mtod(m, struct tcpiphdr *); + adjust: + if (arg.error) { + m_freem(m); + return (EADDRNOTAVAIL); + } + REDUCE(n->ti_sum, n->ti_sum + (0xffff ^ arg.sum)); + } + m->m_len -= sizeof (struct ip); + m->m_pkthdr.len -= sizeof (struct ip); + m->m_data += sizeof (struct ip); + return (clnp_output(m, isop, m->m_pkthdr.len, 0)); +} + +tuba_refcnt(isop, delta) + struct isopcb *isop; +{ + register struct tuba_cache *tc; + unsigned index, sum; + + if (delta != 1) + delta = -1; + if (isop == 0 || isop->isop_faddr == 0 || isop->isop_laddr == 0 || + (delta == -1 && isop->isop_tuba_cached == 0) || + (delta == 1 && isop->isop_tuba_cached != 0)) + return; + isop->isop_tuba_cached = (delta == 1); + if ((index = tuba_lookup(isop->isop_faddr, M_DONTWAIT)) != 0 && + (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0)) + tc->tc_refcnt += delta; + if ((index = tuba_lookup(isop->isop_laddr, M_DONTWAIT)) != 0 && + (tc = tuba_table[index]) != 0 && (delta == 1 || tc->tc_refcnt > 0)) + tc->tc_refcnt += delta; +} + +tuba_pcbdetach(isop) + struct isopcb *isop; +{ + if (isop == 0) + return; + tuba_refcnt(isop, -1); + isop->isop_socket = 0; + iso_pcbdetach(isop); +} + +/* + * Avoid in_pcbconnect in faked out tcp_input() + */ +tuba_pcbconnect(inp, nam) + register struct inpcb *inp; + struct mbuf *nam; +{ + register struct sockaddr_iso *siso; + struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); + struct tcpcb *tp = intotcpcb(inp); + struct isopcb *isop = (struct isopcb *)tp->t_tuba_pcb; + int error; + + /* hardwire iso_pcbbind() here */ + siso = isop->isop_laddr = &isop->isop_sladdr; + *siso = tuba_table[inp->inp_laddr.s_addr]->tc_siso; + siso->siso_tlen = sizeof(inp->inp_lport); + bcopy((caddr_t)&inp->inp_lport, TSEL(siso), sizeof(inp->inp_lport)); + + /* hardwire in_pcbconnect() here without assigning route */ + inp->inp_fport = sin->sin_port; + inp->inp_faddr = sin->sin_addr; + + /* reuse nam argument to call iso_pcbconnect() */ + nam->m_len = sizeof(*siso); + siso = mtod(nam, struct sockaddr_iso *); + *siso = tuba_table[inp->inp_faddr.s_addr]->tc_siso; + siso->siso_tlen = sizeof(inp->inp_fport); + bcopy((caddr_t)&inp->inp_fport, TSEL(siso), sizeof(inp->inp_fport)); + + if ((error = iso_pcbconnect(isop, nam)) == 0) + tuba_refcnt(isop, 1); + return (error); +} + +/* + * CALLED FROM: + * clnp's input routine, indirectly through the protosw. + * FUNCTION and ARGUMENTS: + * Take a packet (m) from clnp, strip off the clnp header + * and do tcp input processing. + * No return value. + */ +tuba_tcpinput(m, src, dst) + register struct mbuf *m; + struct sockaddr_iso *src, *dst; +{ + unsigned long sum, lindex, findex; + register struct tcpiphdr *ti; + register struct inpcb *inp; + caddr_t optp = NULL; + int optlen; + int len, tlen, off; + register struct tcpcb *tp = 0; + int tiflags; + struct socket *so; + int todrop, acked, ourfinisacked, needoutput = 0; + short ostate; + struct in_addr laddr; + int dropsocket = 0, iss = 0; + u_long tiwin, ts_val, ts_ecr; + int ts_present = 0; + + if ((m->m_flags & M_PKTHDR) == 0) + panic("tuba_tcpinput"); + /* + * Do some housekeeping looking up CLNP addresses. + * If we are out of space might as well drop the packet now. + */ + tcpstat.tcps_rcvtotal++; + lindex = tuba_lookup(dst, M_DONTWAIT); + findex = tuba_lookup(src, M_DONTWAIT); + if (lindex == 0 || findex == 0) + goto drop; + /* + * CLNP gave us an mbuf chain WITH the clnp header pulled up, + * but the data pointer pushed past it. + */ + len = m->m_len; + tlen = m->m_pkthdr.len; + m->m_data -= sizeof(struct ip); + m->m_len += sizeof(struct ip); + m->m_pkthdr.len += sizeof(struct ip); + m->m_flags &= ~(M_MCAST|M_BCAST); /* XXX should do this in clnp_input */ + /* + * The reassembly code assumes it will be overwriting a useless + * part of the packet, which is why we need to have it point + * into the packet itself. + * + * Check to see if the data is properly alligned + * so that we can save copying the tcp header. + * This code knows way too much about the structure of mbufs! + */ + off = ((sizeof (long) - 1) & ((m->m_flags & M_EXT) ? + (m->m_data - m->m_ext.ext_buf) : (m->m_data - m->m_pktdat))); + if (off || len < sizeof(struct tcphdr)) { + struct mbuf *m0 = m; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == 0) { + m = m0; + goto drop; + } + m->m_next = m0; + m->m_data += max_linkhdr; + m->m_pkthdr = m0->m_pkthdr; + m->m_flags = m0->m_flags & M_COPYFLAGS; + if (len < sizeof(struct tcphdr)) { + m->m_len = 0; + if ((m = m_pullup(m, sizeof(struct tcpiphdr))) == 0) { + tcpstat.tcps_rcvshort++; + return; + } + } else { + bcopy(mtod(m0, caddr_t) + sizeof(struct ip), + mtod(m, caddr_t) + sizeof(struct ip), + sizeof(struct tcphdr)); + m0->m_len -= sizeof(struct tcpiphdr); + m0->m_data += sizeof(struct tcpiphdr); + m->m_len = sizeof(struct tcpiphdr); + } + } + /* + * Calculate checksum of extended TCP header and data, + * replacing what would have been IP addresses by + * the IP checksum of the CLNP addresses. + */ + ti = mtod(m, struct tcpiphdr *); + ti->ti_dst.s_addr = tuba_table[lindex]->tc_sum; + if (dst->siso_nlen & 1) + ti->ti_src.s_addr = tuba_table[findex]->tc_sum; + else + ti->ti_src.s_addr = tuba_table[findex]->tc_ssum; + ti->ti_prev = ti->ti_next = 0; + ti->ti_x1 = 0; ti->ti_pr = ISOPROTO_TCP; + ti->ti_len = htons((u_short)tlen); + if (ti->ti_sum = in_cksum(m, m->m_pkthdr.len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + ti->ti_src.s_addr = findex; + ti->ti_dst.s_addr = lindex; + /* + * Now include the rest of TCP input + */ +#define TUBA_INCLUDE +#define in_pcbconnect tuba_pcbconnect +#define tcb tuba_inpcb +#define tcp_last_inpcb tuba_last_inpcb + +#include <netinet/tcp_input.c> +} + +#define tcp_slowtimo tuba_slowtimo +#define tcp_fasttimo tuba_fasttimo + +#include <netinet/tcp_timer.c> diff --git a/sys/netiso/tuba_table.c b/sys/netiso/tuba_table.c new file mode 100644 index 0000000..a1bf5f9 --- /dev/null +++ b/sys/netiso/tuba_table.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tuba_table.c 8.2 (Berkeley) 11/15/93 + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/kernel.h> + +#include <net/if.h> +#include <net/radix.h> + +#include <netiso/iso.h> +#include <netiso/tuba_table.h> + +int tuba_table_size; +struct tuba_cache **tuba_table; +struct radix_node_head *tuba_tree; +extern int arpt_keep, arpt_prune; /* use same values as arp cache */ + +void +tuba_timer() +{ + int s = splnet(); + int i; + register struct tuba_cache *tc; + long timelimit = time.tv_sec - arpt_keep; + + timeout(tuba_timer, (caddr_t)0, arpt_prune * hz); + for (i = tuba_table_size; i > 0; i--) + if ((tc = tuba_table[i]) && (tc->tc_refcnt == 0) && + (tc->tc_time < timelimit)) { + tuba_table[i] = 0; + rn_delete(&tc->tc_siso.siso_addr, NULL, tuba_tree); + free((caddr_t)tc, M_RTABLE); + } + splx(s); +} + +tuba_table_init() +{ + rn_inithead((void **)&tuba_tree, 40); + timeout(tuba_timer, (caddr_t)0, arpt_prune * hz); +} + +int +tuba_lookup(siso, wait) + register struct sockaddr_iso *siso; +{ + struct radix_node *rn, *rn_match(); + register struct tuba_cache *tc; + struct tuba_cache **new; + int dupentry = 0, sum_a = 0, sum_b = 0, old_size, i; + + if ((rn = rn_match((caddr_t)&siso->siso_addr, tuba_tree->rnh_treetop)) + && ((rn->rn_flags & RNF_ROOT) == 0)) { + tc = (struct tuba_cache *)rn; + tc->tc_time = time.tv_sec; + return (tc->tc_index); + } + if ((tc = (struct tuba_cache *)malloc(sizeof(*tc), M_RTABLE, wait)) + == NULL) + return (0); + bzero((caddr_t)tc, sizeof (*tc)); + bcopy(siso->siso_data, tc->tc_siso.siso_data, + tc->tc_siso.siso_nlen = siso->siso_nlen); + rn_insert(&tc->tc_siso.siso_addr, tuba_tree, &dupentry, tc->tc_nodes); + if (dupentry) + panic("tuba_lookup 1"); + tc->tc_siso.siso_family = AF_ISO; + tc->tc_siso.siso_len = sizeof(tc->tc_siso); + tc->tc_time = time.tv_sec; + for (i = sum_a = tc->tc_siso.siso_nlen; --i >= 0; ) + (i & 1 ? sum_a : sum_b) += (u_char)tc->tc_siso.siso_data[i]; + REDUCE(tc->tc_sum, (sum_a << 8) + sum_b); + HTONS(tc->tc_sum); + SWAB(tc->tc_ssum, tc->tc_sum); + for (i = tuba_table_size; i > 0; i--) + if (tuba_table[i] == 0) + goto fixup; + old_size = tuba_table_size; + if (tuba_table_size == 0) + tuba_table_size = 15; + if (tuba_table_size > 0x7fff) + return (0); + tuba_table_size = 1 + 2 * tuba_table_size; + i = (tuba_table_size + 1) * sizeof(tc); + new = (struct tuba_cache **)malloc((unsigned)i, M_RTABLE, wait); + if (new == 0) { + tuba_table_size = old_size; + rn_delete(&tc->tc_siso.siso_addr, NULL, tuba_tree); + free((caddr_t)tc, M_RTABLE); + return (0); + } + bzero((caddr_t)new, (unsigned)i); + if (tuba_table) { + bcopy((caddr_t)tuba_table, (caddr_t)new, i >> 1); + free((caddr_t)tuba_table, M_RTABLE); + } + tuba_table = new; + i = tuba_table_size; +fixup: + tuba_table[i] = tc; + tc->tc_index = i; + return (tc->tc_index); +} diff --git a/sys/netiso/tuba_table.h b/sys/netiso/tuba_table.h new file mode 100644 index 0000000..6be8afa --- /dev/null +++ b/sys/netiso/tuba_table.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tuba_table.h 8.1 (Berkeley) 6/10/93 + */ + +struct tuba_cache { + struct radix_node tc_nodes[2]; /* convenient lookup */ + int tc_refcnt; + int tc_time; /* last looked up */ + int tc_flags; +#define TCF_PERM 1 + int tc_index; + u_short tc_sum; /* cksum of nsap inc. length */ + u_short tc_ssum; /* swab(tc_sum) */ + struct sockaddr_iso tc_siso; /* for responding */ +}; + +#define ADDCARRY(x) (x >= 65535 ? x -= 65535 : x) +#define REDUCE(a, b) { union { u_short s[2]; long l;} l_util; long x; \ + l_util.l = (b); x = l_util.s[0] + l_util.s[1]; ADDCARRY(x); \ + if (x == 0) x = 0xffff; a = x;} +#define SWAB(a, b) { union { u_char c[2]; u_short s;} s; u_char t; \ + s.s = (b); t = s.c[0]; s.c[0] = s.c[1]; s.c[1] = t; a = s.s;} + +#ifdef KERNEL +extern int tuba_table_size; +extern struct tuba_cache **tuba_table; +extern struct radix_node_head *tuba_tree; +#endif diff --git a/sys/netiso/tuba_usrreq.c b/sys/netiso/tuba_usrreq.c new file mode 100644 index 0000000..2d92117 --- /dev/null +++ b/sys/netiso/tuba_usrreq.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tuba_usrreq.c 8.1 (Berkeley) 6/10/93 + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/protosw.h> +#include <sys/errno.h> +#include <sys/stat.h> + +#include <net/if.h> +#include <net/route.h> + +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/in_pcb.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_fsm.h> +#include <netinet/tcp_seq.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/tcpip.h> +#include <netinet/tcp_debug.h> + +#include <netiso/argo_debug.h> +#include <netiso/iso.h> +#include <netiso/clnp.h> +#include <netiso/iso_pcb.h> +#include <netiso/iso_var.h> +#include <netiso/tuba_table.h> +/* + * TCP protocol interface to socket abstraction. + */ +extern char *tcpstates[]; +extern struct inpcb tuba_inpcb; +extern struct isopcb tuba_isopcb; + +/* + * Process a TCP user request for TCP tb. If this is a send request + * then m is the mbuf chain of send data. If this is a timer expiration + * (called from the software clock routine), then timertype tells which timer. + */ +/*ARGSUSED*/ +tuba_usrreq(so, req, m, nam, control) + struct socket *so; + int req; + struct mbuf *m, *nam, *control; +{ + register struct inpcb *inp; + register struct isopcb *isop; + register struct tcpcb *tp; + int s; + int error = 0; + int ostate; + struct sockaddr_iso *siso; + + if (req == PRU_CONTROL) + return (iso_control(so, (int)m, (caddr_t)nam, + (struct ifnet *)control)); + + s = splnet(); + inp = sotoinpcb(so); + /* + * When a TCP is attached to a socket, then there will be + * a (struct inpcb) pointed at by the socket, and this + * structure will point at a subsidary (struct tcpcb). + */ + if (inp == 0 && req != PRU_ATTACH) { + splx(s); + return (EINVAL); /* XXX */ + } + if (inp) { + tp = intotcpcb(inp); + if (tp == 0) + panic("tuba_usrreq"); + ostate = tp->t_state; + isop = (struct isopcb *)tp->t_tuba_pcb; + if (isop == 0) + panic("tuba_usrreq 2"); + } else + ostate = 0; + switch (req) { + + /* + * TCP attaches to socket via PRU_ATTACH, reserving space, + * and an internet control block. We also need to + * allocate an isopcb and separate the control block from + * tcp/ip ones. + */ + case PRU_ATTACH: + if (error = iso_pcballoc(so, &tuba_isopcb)) + break; + isop = (struct isopcb *)so->so_pcb; + so->so_pcb = 0; + if (error = tcp_usrreq(so, req, m, nam, control)) { + isop->isop_socket = 0; + iso_pcbdetach(isop); + } else { + inp = sotoinpcb(so); + remque(inp); + insque(inp, &tuba_inpcb); + inp->inp_head = &tuba_inpcb; + tp = intotcpcb(inp); + if (tp == 0) + panic("tuba_usrreq 3"); + tp->t_tuba_pcb = (caddr_t) isop; + } + goto notrace; + + /* + * PRU_DETACH detaches the TCP protocol from the socket. + * If the protocol state is non-embryonic, then can't + * do this directly: have to initiate a PRU_DISCONNECT, + * which may finish later; embryonic TCB's can just + * be discarded here. + */ + case PRU_DETACH: + if (tp->t_state > TCPS_LISTEN) + tp = tcp_disconnect(tp); + else + tp = tcp_close(tp); + if (tp == 0) + tuba_pcbdetach(isop); + break; + + /* + * Give the socket an address. + */ + case PRU_BIND: + siso = mtod(nam, struct sockaddr_iso *); + if (siso->siso_tlen && siso->siso_tlen != 2) { + error = EINVAL; + break; + } + if ((error = iso_pcbbind(isop, nam)) || + (siso = isop->isop_laddr) == 0) + break; + bcopy(TSEL(siso), &inp->inp_lport, 2); + if (siso->siso_nlen && + !(inp->inp_laddr.s_addr = tuba_lookup(siso, M_WAITOK))) + error = ENOBUFS; + break; + + /* + * Prepare to accept connections. + */ + case PRU_CONNECT: + case PRU_LISTEN: + if (inp->inp_lport == 0 && + (error = iso_pcbbind(isop, (struct mbuf *)0))) + break; + bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); + if (req == PRU_LISTEN) { + tp->t_state = TCPS_LISTEN; + break; + } + /*FALLTHROUGH*/ + /* + * Initiate connection to peer. + * Create a template for use in transmissions on this connection. + * Enter SYN_SENT state, and mark socket as connecting. + * Start keep-alive timer, and seed output sequence space. + * Send initial segment on connection. + */ + /* case PRU_CONNECT: */ + if (error = iso_pcbconnect(isop, nam)) + break; + if ((siso = isop->isop_laddr) && siso->siso_nlen > 1) + siso->siso_data[siso->siso_nlen - 1] = ISOPROTO_TCP; + else + panic("tuba_usrreq: connect"); + siso = mtod(nam, struct sockaddr_iso *); + if (!(inp->inp_faddr.s_addr = tuba_lookup(siso, M_WAITOK))) { + unconnect: + iso_pcbdisconnect(isop); + error = ENOBUFS; + break; + } + bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); + if (inp->inp_laddr.s_addr == 0 && + (inp->inp_laddr.s_addr = + tuba_lookup(isop->isop_laddr, M_WAITOK)) == 0) + goto unconnect; + if ((tp->t_template = tcp_template(tp)) == 0) + goto unconnect; + soisconnecting(so); + tcpstat.tcps_connattempt++; + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + error = tcp_output(tp); + tuba_refcnt(isop, 1); + break; + + /* + * Initiate disconnect from peer. + * If connection never passed embryonic stage, just drop; + * else if don't need to let data drain, then can just drop anyways, + * else have to begin TCP shutdown process: mark socket disconnecting, + * drain unread data, state switch to reflect user close, and + * send segment (e.g. FIN) to peer. Socket will be really disconnected + * when peer sends FIN and acks ours. + * + * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. + */ + case PRU_DISCONNECT: + if ((tp = tcp_disconnect(tp)) == 0) + tuba_pcbdetach(isop); + break; + + /* + * Accept a connection. Essentially all the work is + * done at higher levels; just return the address + * of the peer, storing through addr. + */ + case PRU_ACCEPT: + bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), + nam->m_len = isop->isop_faddr->siso_len); + break; + + /* + * Mark the connection as being incapable of further output. + */ + case PRU_SHUTDOWN: + socantsendmore(so); + tp = tcp_usrclosed(tp); + if (tp) + error = tcp_output(tp); + else + tuba_pcbdetach(isop); + break; + /* + * Abort the TCP. + */ + case PRU_ABORT: + if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) + tuba_pcbdetach(isop); + break; + + + case PRU_SOCKADDR: + if (isop->isop_laddr) + bcopy((caddr_t)isop->isop_laddr, mtod(nam, caddr_t), + nam->m_len = isop->isop_laddr->siso_len); + break; + + case PRU_PEERADDR: + if (isop->isop_faddr) + bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), + nam->m_len = isop->isop_faddr->siso_len); + break; + + default: + error = tcp_usrreq(so, req, m, nam, control); + goto notrace; + } + if (tp && (so->so_options & SO_DEBUG)) + tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); +notrace: + splx(s); + return(error); +} + +tuba_ctloutput(op, so, level, optname, mp) + int op; + struct socket *so; + int level, optname; + struct mbuf **mp; +{ + int clnp_ctloutput(), tcp_ctloutput(); + + return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) + (op, so, level, optname, mp)); +} diff --git a/sys/netiso/xebec/Makefile b/sys/netiso/xebec/Makefile new file mode 100644 index 0000000..fa05f9c --- /dev/null +++ b/sys/netiso/xebec/Makefile @@ -0,0 +1,8 @@ +# @(#)Makefile 5.16 (Berkeley) 4/26/91 + +PROG= xebec +SRCS= llparse.c llscan.c main.c malloc.c procs.c putdriver.c sets.c xebec.c +CFLAGS+= -DDEBUG -traditional +NOMAN = noman + +.include <bsd.prog.mk> diff --git a/sys/netiso/xebec/debug.h b/sys/netiso/xebec/debug.h new file mode 100644 index 0000000..2e3f167 --- /dev/null +++ b/sys/netiso/xebec/debug.h @@ -0,0 +1,22 @@ +/* $Header: debug.h,v 2.1 88/09/19 12:56:16 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/debug.h,v $ */ + +#define OUT stdout + +extern int debug[128]; + +#ifdef DEBUG +extern int column; + +#define IFDEBUG(letter) \ + if(debug['letter']) { +#define ENDDEBUG ; (void) fflush(stdout);} + +#else + +#define STAR * +#define IFDEBUG(letter) //*beginning of comment*/STAR +#define ENDDEBUG STAR/*end of comment*// + +#endif DEBUG + diff --git a/sys/netiso/xebec/llparse.c b/sys/netiso/xebec/llparse.c new file mode 100644 index 0000000..fee7a9f --- /dev/null +++ b/sys/netiso/xebec/llparse.c @@ -0,0 +1,366 @@ +/* $Header: llparse.c,v 2.2 88/09/19 12:54:59 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/llparse.c,v $ */ +/* + * ************************* NOTICE ******************************* + * This code is in the public domain. It cannot be copyrighted. + * This ll parser was originally written by Keith Thompson for the + * University of Wisconsin Crystal project. + * It was based on an FMQ lr parser written by Jon Mauney at the + * University of Wisconsin. + * It was subsequently modified very slightly by Nancy Hall at the + * University of Wisconsin for the Crystal project. + * **************************************************************** + */ +#include "xebec.h" +#include "llparse.h" +#include "main.h" +#include <stdio.h> + +#include "debug.h" + +#define LLMINACTION -LLINF + +short llparsestack[STACKSIZE]; +short llstackptr = 0; +LLtoken lltoken; + +llparse() +{ + register havetoken = FALSE; + register sym; + register LLtoken *t = &lltoken; + register parseaction; + register accepted = FALSE; + + llpushprod(llnprods-1); /* $$$ ::= <start symbol> */ + + do { + sym = llparsestack[llstackptr]; + IFDEBUG(L) + printf("llparse() top of loop, llstackptr=%d, sym=%d\n", + llstackptr, sym); + ENDDEBUG + + if(sym < 0) { + /* action symbol */ + if(sym <= LLMINACTION) { + for(;sym<=LLMINACTION;sym++) { + llaction(1, t); /* calls llfinprod */ + } + llstackptr--; + continue; + } else { llaction(-sym, t); + llstackptr--; + continue; + } + } + + if(sym < llnterms) { + + /* it's a terminal symbol */ + + if(!havetoken) { + llgettoken(t); + havetoken = TRUE; + } + + if(sym == t->llterm) { + llpushattr(t->llattrib); + llaccept(t); + llstackptr--; /* pop terminal */ + if(t->llterm == llnterms-1) { /* end symbol $$$ */ + accepted = TRUE; + } else { + havetoken = FALSE; + } + } else { + llparsererror(t); /* wrong terminal on input */ + havetoken = FALSE; + } + continue; + } + + /* non terminal */ + + if(!havetoken) { + llgettoken(t); + havetoken = TRUE; + } + + /* consult parse table for new production */ + parseaction = llfindaction(sym, t->llterm); + + if(parseaction == 0) { + /* error entry */ + llparsererror(t); + havetoken = FALSE; + continue; + } + + if(llepsilon[parseaction]) { + /* epsilon production */ + if(llepsilonok(t->llterm)) { + llstackptr--; /* pop nonterminal */ + llpushprod(parseaction); /* push rhs of production */ + } else { + llparsererror(t); + havetoken = FALSE; + } + } else { + llstackptr--; /* pop nonterminal */ + llpushprod(parseaction); /* push rhs of production */ + } + } while(!accepted); + + return(0); +} + +llpushprod(prod) /* recognize production prod - push rhs on stack */ +short prod; +{ + register start; + register length; + register count; + + start = llprodindex[prod].llprodstart; + length = llprodindex[prod].llprodlength; + + IFDEBUG(L) + printf("llpushprod(%d) llstackptr=0x%x(%d), length = 0x%x(%d)\n", + prod, llstackptr, llstackptr, length , length); + /* + dump_parse_stack(); + */ + ENDDEBUG + if(llstackptr+length >= STACKSIZE) { + fprintf(stderr,"Parse stack overflow. llstackptr=0x%x, length=0x%x\n", + llstackptr, length); + Exit(-1); + } + + + llsetattr(llprodindex[prod].llprodtlen); + + /* put a marker on the stack to mark beginning of production */ + if(llparsestack[llstackptr] <= LLMINACTION) { + (llparsestack[llstackptr]) --; /* if there's already one there, don't + put another on; just let it represent all of + the adjacent markers */ + } + else { + llstackptr++; + llparsestack[llstackptr] = LLMINACTION; + } + + for(count=0; count<length; count++) { + llstackptr++; + llparsestack[llstackptr] = llproductions[start++]; + } + if(llstackptr > STACKSIZE) { + fprintf(stderr, "PARSE STACK OVERFLOW! \n"); Exit(-1); + Exit(-1); + } +} + + +llepsilonok(term) +{ + register ptr; + register sym; + register pact; + register nomore; + register rval; + + IFDEBUG(L) + printf("llepsilonok() enter\n"); + ENDDEBUG + rval = TRUE; + + ptr = llstackptr; + + do { + sym = llparsestack[ptr]; + + if(sym < 0) { + ptr--; + nomore = ptr == 0; + continue; + } + + if(sym < llnterms) { + nomore = TRUE; + rval = sym == term; + continue; + } + + pact = llfindaction(sym, term); + + if(pact == 0) { + nomore = TRUE; + rval = FALSE; + continue; + } + + if(llepsilon[pact] == TRUE) { + ptr--; + nomore = ptr == 0; + } + else { + nomore = TRUE; + } + + } while(!nomore); + + return(rval); +} + + +short llfindaction(sym, term) +{ + register index; + + IFDEBUG(L) + printf("llfindaction(sym=%d, term=%d) enter \n", sym, term); + ENDDEBUG + index = llparseindex[sym]; + + while(llparsetable[index].llterm != 0) { + if(llparsetable[index].llterm == term) { + return(llparsetable[index].llprod); + } + index++; + } + return(0); +} + + +llparsererror(token) +LLtoken *token; +{ + IFDEBUG(L) + fprintf(stderr,"llparsererror() enter\n"); + prt_token(token); + ENDDEBUG + + fprintf(stderr, "Syntax error: "); + prt_token(token); + dump_buffer(); + Exit(-1); +} + + +llgettoken(token) +LLtoken *token; +{ + llscan(token); + token->llstate = NORMAL; + IFDEBUG(L) + printf("llgettoken(): "); + prt_token(token); + ENDDEBUG +} + + +/****************************************************************************** + + Attribute support routines + +******************************************************************************/ +/* +** attribute stack +** +** AttrStack = stack of record +** values : array of values; +** ptr : index; +** end; +** +*/ + +LLattrib llattributes[LLMAXATTR]; +int llattrtop = 0; + +struct llattr llattrdesc[LLMAXDESC]; + +int lldescindex = 1; + + +llsetattr(n) +{ + register struct llattr *ptr; + + IFDEBUG(L) + printf("llsetattr(%d) enter\n",n); + ENDDEBUG + if(lldescindex >= LLMAXDESC) { + fprintf(stdout, "llattribute stack overflow: desc\n"); + fprintf(stdout, + "lldescindex=0x%x, llattrtop=0x%x\n",lldescindex, llattrtop); + Exit(-1); + } + ptr = &llattrdesc[lldescindex]; + ptr->llabase = &llattributes[llattrtop]; + ptr->lloldtop = ++llattrtop; + ptr->llaindex = 1; + ptr->llacnt = n+1; /* the lhs ALWAYS uses an attr; it remains on the + stack when the production is recognized */ + lldescindex++; +} + +llpushattr(attr) +LLattrib attr; +{ + struct llattr *a; + + IFDEBUG(L) + printf("llpushattr() enter\n"); + ENDDEBUG + if(llattrtop + 1 > LLMAXATTR) { + fprintf(stderr, "ATTRIBUTE STACK OVERFLOW!\n"); + Exit(-1); + } + a = &llattrdesc[lldescindex-1]; + llattributes[llattrtop++] = attr; + a->llaindex++; /* inc count of attrs on the stack for this prod */ +} + +llfinprod() +{ + IFDEBUG(L) + printf("llfinprod() enter\n"); + ENDDEBUG + lldescindex--; + llattrtop = llattrdesc[lldescindex].lloldtop; + llattrdesc[lldescindex-1].llaindex++; /* lhs-of-prod.attr stays on + the stack; it is now one of the rhs attrs of the now-top production + on the stack */ +} + +#ifndef LINT +#ifdef DEBUG +dump_parse_stack() +{ + int ind; + + printf("PARSE STACK:\n"); + for(ind=llstackptr; ind>=0; ind--) { + printf("%d\t%d\t%s\n", + ind, llparsestack[ind], + llparsestack[ind]<0? "Action symbol" : llstrings[llparsestack[ind]]); + } +} + +#endif DEBUG +#endif LINT + +prt_token(t) +LLtoken *t; +{ + fprintf(stdout, "t at 0x%x\n", t); + fprintf(stdout, "t->llterm=0x%x\n", t->llterm); (void) fflush(stdout); + fprintf(stdout, "TOK: %s\n", llstrings[t->llterm]); + (void) fflush(stdout); +#ifdef LINT + /* to make lint shut up */ + fprintf(stdout, "", llnterms, llnsyms, llnprods, llinfinite); +#endif LINT +} diff --git a/sys/netiso/xebec/llparse.h b/sys/netiso/xebec/llparse.h new file mode 100644 index 0000000..1b6133b --- /dev/null +++ b/sys/netiso/xebec/llparse.h @@ -0,0 +1,145 @@ +/* $Header: llparse.h,v 2.1 88/09/19 12:56:20 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/llparse.h,v $ */ + + /************************************************************ + attributes stack garbage + ************************************************************/ + +#define LLMAXATTR 512 +#define LLMAXDESC 256 +#define LLATTR /* build an attribute stack */ + + /* + ** attribute stack + ** + ** AttrStack = stack of record + ** values : array of values; + ** ptr : index; + ** end; + ** + */ + + typedef union llattrib LLattrib; + + extern LLattrib llattributes[LLMAXATTR]; + extern int llattrtop; + + extern struct llattr { + LLattrib *llabase; /* ptr into the attr stack (llattributes) */ + int llaindex;/* # attrs on the stack so far for this prod */ + int llacnt;/* total # ever to go on for this prod */ + + int lloldtop;/* when popping this prod, restore stack to here ; + one attr will remain on the stack (for the lhs) */ + } llattrdesc[LLMAXDESC]; + + extern int lldescindex; + + /************************************************************ + attributes stack garbage + ************************************************************/ + + extern struct lltoken { + short llterm; /* token number */ + short llstate; /* inserted deleted normal */ + LLattrib llattrib; + } lltoken; + typedef struct lltoken LLtoken; + +/************************************************************ + constants used in llparse.c +************************************************************/ + +#define STACKSIZE 500 +#define MAXCORR 16 + +#define NORMAL 0 +#define DELETE 1 +#define INSERT 2 + +/************************************************************ + datatypes used to communicate with the parser +************************************************************/ + +struct llinsert { + short llinscost; + short llinslength; + short llinsert[MAXCORR]; +}; +typedef struct llinsert LLinsert; + +extern short llparsestack[]; +extern short llstackptr; +extern short llinfinite; + +/************************************************************ + variables used to pass information + specific to each grammer +************************************************************/ + +extern short llnterms; +extern short llnsyms; +extern short llnprods; + +extern char *llefile; + +extern struct llparsetable { + short llterm; + short llprod; +} llparsetable[]; + +extern short llparseindex[]; + +extern short llepsilon[]; + +extern short llproductions[]; + +extern struct llprodindex { + short llprodstart; + short llprodlength; + short llprodtlen; +} llprodindex[]; + +extern struct llcosts { + short llinsert; + short lldelete; +} llcosts[]; + +extern struct llstable { + short llsstart; + short llslength; +} llstable[]; + +extern short llsspace[]; + +extern struct lletable { + short llecost; + short llelength; + short llestart; +} lletable[]; + +extern long lleindex[]; + +extern short llespace[]; + +extern char *llstrings[]; + +/************************************************************ + routines defined in llparse.c +************************************************************/ + +extern llparse(); +extern llcopye(); +extern llcopys(); +extern llcorrector(); +extern llepsilonok(); +extern llexpand(); +extern short llfindaction(); +extern llgetprefix(); +extern llgettoken(); +extern llinsert(); +extern llinsertsym(); +extern llinserttokens(); +extern llparsererror(); +extern llpushprod(); +extern llreadetab(); diff --git a/sys/netiso/xebec/llscan.c b/sys/netiso/xebec/llscan.c new file mode 100644 index 0000000..ffdb9a9 --- /dev/null +++ b/sys/netiso/xebec/llscan.c @@ -0,0 +1,430 @@ +/* $Header: llscan.c,v 2.2 88/09/19 12:55:06 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/llscan.c,v $ */ +/* + * ************************* NOTICE ******************************* + * This code is in the public domain. It cannot be copyrighted. + * This scanner was originally written by Keith Thompson for the + * University of Wisconsin Crystal project. + * It was subsequently modified significantly by Nancy Hall at the + * University of Wisconsin for the ARGO project. + * **************************************************************** + */ +#include "xebec.h" +#include "llparse.h" + +#include "main.h" +#include <stdio.h> +#include "procs.h" +#include "debug.h" + +#define EOFILE 0x01 +#define UNUSED 0x02 +#define IGNORE 0x04 +#define OPCHAR 0x8 +#define DIGITS 0x10 +#define LETTER 0x20 + +int chtype[128] = { +/* null, soh ^a, stx ^b etx ^c eot ^d enq ^e ack ^f bel ^g */ + EOFILE, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, +/* bs ^h ht ^i lf ^j vt ^k ff ^l cr ^m so ^n si ^o */ + UNUSED, IGNORE, IGNORE, UNUSED, IGNORE, IGNORE, UNUSED, UNUSED, +/* dle ^p dc1 ^q dc2 ^r dc3 ^s dc4 ^t nak ^u syn ^v etb ^w */ + UNUSED, UNUSED, UNUSED, UNUSED, EOFILE, UNUSED, UNUSED, UNUSED, +/* can ^x em ^y sub ^z esc ^] fs ^\ gs ^} rs ^` us ^/ */ + UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, + +/* ! " # $ % & ' */ + IGNORE, UNUSED, OPCHAR, UNUSED, OPCHAR, UNUSED, OPCHAR, OPCHAR, +/* ( ) * + , - . / */ + OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, +/* 0 1 2 3 4 5 6 7 */ + DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, +/* 8 9 : ; < = > ? */ + DIGITS, DIGITS, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, + +/* @ A B C D E F G */ + UNUSED, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* H I J K L M N O */ + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* P Q R S T U V W */ + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* X Y Z [ \ ] ^ _ */ + LETTER, LETTER, LETTER, OPCHAR, UNUSED, OPCHAR, OPCHAR, LETTER, + +/* ` a b c d e f g */ + UNUSED, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* h i j k l m n o */ + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* p q r s t u v w */ + LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* x y z { | } ~ del */ + LETTER, LETTER, LETTER, OPCHAR, UNUSED, OPCHAR, UNUSED, UNUSED +}; + + +extern FILE *astringfile; +static char *buffptr; +static char buffer[2][LINELEN]; +static int currentbuf = 1; + +#define addbuf(x) *buffptr++ = x + +static int ch = ' '; + +skip() +{ + while((chtype[ch] == IGNORE) ) { + ch = getch(); + } +} + +llaccept(t) +LLtoken *t; +{ + switch(t->llstate) { + case NORMAL: + break; + case INSERT: + fprintf(stderr,"Insert %s\n", llstrings[t->llterm]); + break; + case DELETE: + fprintf(stderr,"Delete %s\n", llstrings[t->llterm]); + break; + } +} + +#define TVAL (t->llattrib) + + +dump_buffer() +{ + register int i; + for(i=0; i<20; i++) + (void) fputc(buffer[currentbuf][i], stderr); + (void) fputc('\n', stderr); + (void) fflush(stderr); +} + +int iskey(c, buf) +char *c; +char **buf; +{ + register int i; + static struct { char *key_word; int term_type; } keys[] = { + { "SAME", T_SAME }, + { "DEFAULT", T_DEFAULT }, + { "NULLACTION", T_NULLACTION }, + { "STRUCT", T_STRUCT }, + { "SYNONYM", T_SYNONYM }, + { "TRANSITIONS", T_TRANSITIONS }, + { "STATES", T_STATES }, + { "EVENTS", T_EVENTS }, + { "PCB", T_PCB }, + { "INCLUDE", T_INCLUDE }, + { "PROTOCOL", T_PROTOCOL }, + { 0, 0}, + }; + + for (i = 0; keys[i].key_word ; i++) { + if( !strcmp(c, (*buf = keys[i].key_word) ) ) { + return ( keys[i].term_type ); + } + } + *buf = (char *)0; + return(0); +} + +getstr(o,c) + /* c is the string delimiter + * allow the delimiter to be escaped + * the messy part: translate $ID to + * e->ev_union.ID + * where ID is an event with a non-zero obj_struc + * need we check for the field??? + */ +char o,c; +{ + register int nested = 1; + register int allow_nesting = (o==c)?-1:1; + + IFDEBUG(S) + fprintf(stdout,"getstr: ch=%c, delimiters %c %c\n", + ch,o, c); + fprintf(stdout,"getstr: buffptr 0x%x, currentbuf 0x%x\n", + buffptr, currentbuf); + ENDDEBUG + + if( ch == c ) nested--; + while(nested) { + if(ch == '\0') { + fprintf(stderr, + "Eof inside of a string, delims= %c,%c, nesting %d",c,o, nested); + Exit(-1); + /* notreached */ + } else if(ch == '$') { + /* might be an attribute */ + IFDEBUG(S) + fprintf(stdout,"getstr: atttribute?\n"); + ENDDEBUG + + /* assume it's an event */ + /* addbuf is a macro so this isn't as bad as + * it looks + * add "e->ev_union." + */ + if( (ch = getch()) == '$' ) { + addbuf('e'); addbuf('-'); addbuf('>'); + addbuf('e'); addbuf('v'); addbuf('_'); + addbuf('u'); addbuf('n'); addbuf('i'); + addbuf('o'); addbuf('n'); + addbuf('.'); + AddCurrentEventName(& buffptr); + } else { + char *obufp = buffptr; + + do { + addbuf(ch); + ch = getch(); + } while(chtype[ch] & LETTER); + addbuf('\0'); + if( !strncmp(obufp, synonyms[PCB_SYN], + strlen(synonyms[PCB_SYN]) )) { + buffptr = obufp; + addbuf('p'); + } else if( !strncmp(obufp, synonyms[EVENT_SYN], + strlen(synonyms[EVENT_SYN]))) { + buffptr = obufp; + addbuf('e'); + } else { + fprintf(stderr, "Unknown synonym %s\n", obufp); + Exit(-1); + } + if(ch == '.') { + addbuf('-'); addbuf('>'); + } else { + /* needs to be checked for nesting */ + goto check; + } + } + /* end of attribute handling */ + goto skip; + } else if(ch == '\\') { + /* possible escape - this is kludgy beyond belief: + * \ is used to escape open and closing delimiters + * and '$' + * otherwise it's passed through to be compiled by C + */ + ch = getch(); + if( (ch != o ) && (ch != c) && (ch != '$') ) { + /* may need to handle case where \ is last char in file... */ + /* don't treat is as escape; not open or close so + * don't have to worry about nesting either + */ + addbuf('\\'); + } + } + addbuf(ch); + skip: + ch = getch(); + check: + if( ch == o ) nested += allow_nesting; + else if( ch == c ) nested--; + if ( (buffptr - buffer[currentbuf]) > LINELEN) { + fprintf(stderr, + "%s too long.\n", (o=='{')?"Action":"Predicate"); /*}*/ + fprintf(stderr, + "buffptr, currentbuf 0x%x, 0x%x\n",buffptr,currentbuf ); + Exit(-1); + } + IFDEBUG(S) + fprintf(stdout,"loop in getstr: ch 0x%x,%c o=%c,c=%c nested=%d\n", + ch,ch,o,c,nested); + ENDDEBUG + } + addbuf(ch); + addbuf('\0'); + + IFDEBUG(S) + fprintf(stdout,"exit getstr: got %s\n", buffer[currentbuf]); + fprintf(stdout,"exit getstr: buffptr 0x%x, currentbuf 0x%x\n", + buffptr, currentbuf); + ENDDEBUG +} + +getch() +{ + char c; + extern FILE *infile; + extern int lineno; + + c = fgetc(infile) ; + if (c == '\n') lineno++; + if ((int)c == EOF) c = (char)0; + if (feof(infile)) c = (char) 0; + IFDEBUG(e) + fprintf(stdout, "getch: 0x%x\n", c); + (void) fputc( c, stdout); + fflush(stdout); + ENDDEBUG + + return c; +} + +llscan(t) +LLtoken *t; +{ + char c; + + t->llstate = NORMAL; + + ++currentbuf; + currentbuf&=1; +again: + buffptr = &buffer[currentbuf][0]; + + skip(); + + switch(chtype[ch]) { + + case EOFILE: + t->llterm = T_ENDMARKER; + break; + + case UNUSED: + fprintf(stderr, "Illegal character in input - 0x%x ignored.", ch); + ch = getch(); + goto again; + + case OPCHAR: + + switch(ch) { + + case '/': + /* possible comment : elide ; kludge */ + IFDEBUG(S) + fprintf(stdout, "Comment ch=%c\n", ch); + ENDDEBUG + c = getch(); + if (c != '*') { + fprintf(stderr,"Syntax error : character(0x%x) ignored", ch); + ch = c; + goto again; + } else { + register int state = 2, whatchar=0; + static int dfa[3][3] = { + /* done seen-star middle */ + /* star */ { 0, 1, 1 }, + /* / */ { 0, 0, 2 }, + /* other */ { 0, 2, 2 } + }; + + while( state ) { + if( (c = getch()) == (char)0) + break; + whatchar = (c=='*')?0:(c=='/'?1:2); + IFDEBUG(S) + fprintf(stdout, + "comment: whatchar = %d, c = 0x%x,%c, oldstate=%d", + whatchar, c,c, state); + ENDDEBUG + state = dfa[whatchar][state]; + IFDEBUG(S) + fprintf(stdout, ", newstate=%d\n", state); + ENDDEBUG + } + if(state) { + fprintf(stderr, + "Syntax error: end of file inside a comment"); + Exit(-1); + } else ch = getch(); + } + IFDEBUG(S) + fprintf(stdout, "end of comment at 0x%x,%c\n",ch,ch); + ENDDEBUG + goto again; + + + case '*': + t->llterm = T_STAR; + break; + + case ',': + t->llterm = T_COMMA; + break; + + case ';': + t->llterm = T_SEMI; + break; + + case '<': + t->llterm = T_LANGLE; + break; + + case '=': + t->llterm = T_EQUAL; + break; + + case '[': + t->llterm = T_LBRACK; + break; + + case ']': + t->llterm = T_RBRACK; + break; + +#ifdef T_FSTRING + case '"': + t->llterm = T_FSTRING; + addbuf(ch); + ch = getch(); + getstr('"', '"'); + TVAL.FSTRING.address = stash(buffer[currentbuf]); + break; +#endif T_FSTRING + + case '(': + t->llterm = T_PREDICATE; + getstr(ch, ')' ); + TVAL.PREDICATE.address = buffer[currentbuf]; + break; + + case '{': + t->llterm = T_ACTION; + getstr(ch, '}'); + TVAL.ACTION.address = buffer[currentbuf]; + break; + + default: + fprintf(stderr,"Syntax error : character(0x%x) ignored", ch); + ch = getch(); + goto again; + + } + ch = getch(); + break; + + case LETTER: + do { + addbuf(ch); + ch = getch(); + } while(chtype[ch] & (LETTER | DIGITS)); + + addbuf('\0'); + + t->llterm = iskey(buffer[currentbuf], &TVAL.ID.address); + if(!t->llterm) { + t->llterm = T_ID; + TVAL.ID.address = buffer[currentbuf]; + } + IFDEBUG(S) + fprintf(stdout, "llscan: id or keyword 0x%x, %s\n", + TVAL.ID.address, TVAL.ID.address); + ENDDEBUG + break; + + default: + fprintf(stderr, "Snark in llscan: chtype=0x%x, ch=0x%x\n", + chtype[ch], ch); + } +} diff --git a/sys/netiso/xebec/main.c b/sys/netiso/xebec/main.c new file mode 100644 index 0000000..a0b4842 --- /dev/null +++ b/sys/netiso/xebec/main.c @@ -0,0 +1,410 @@ +/* $Header: main.c,v 2.4 88/09/19 12:55:13 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/main.c,v $ */ +/* + * TODO: + * rewrite the command line stuff altogether - it's kludged beyond + * belief (as is the rest of the code...) + * + * DISCLAIMER DISCLAIMER DISCLAIMER + * This code is such a kludge that I don't want to put my name on it. + * It was a ridiculously fast hack and needs rewriting. + * However it does work... + */ + +#include <stdio.h> +#include <strings.h> +#include "malloc.h" +#include "debug.h" +#include "main.h" + +int debug[128]; + +int lineno = 1; + +FILE *statefile, *actfile, *eventfile_h, *statevalfile; +FILE *infile, *astringfile; +char *Transfilename; +char *astringfile_name = DEBUGFILE; +char *actfile_name = ACTFILE; +char *statefile_name = STATEFILE; +char *statevalfile_name = STATEVALFILE; +char *eventfile_h_name = EVENTFILE_H; +int print_trans = 0; +int print_protoerrs = 0; +int pgoption = 0; +char kerneldirname[50] = "\0"; + +char protocol[50]; + +char *synonyms[] = { + "EVENT", + "PCB", + 0 +}; + +usage(a) +char *a; +{ + fprintf(stderr, + "usage: %s <transition file> {-D<debug options>} <other options>\n", + a); + fprintf(stderr, "\t<other options> is any combination of:\n"); + fprintf(stderr, "\t\t-A<action file name>\n"); + fprintf(stderr, "\t\t-E<event file name>\n"); + fprintf(stderr, "\t\t-S<state file name>\n"); + fprintf(stderr, "\t\t-I<initial values file name>\n"); + fprintf(stderr, "\t\t-X<debugging file name>\n"); + fprintf(stderr, "\t\t-K<directory name>\n"); + fprintf(stderr, + "\tThese names do NOT include the suffices (.c, .h)\n"); + fprintf(stderr, + "\t\t-D<options> to turn on debug options for xebec itself\n"); + fprintf(stderr, "\t-<nn> for levels of debugging output\n"); + fprintf(stderr, "\t\t<nn> ranges from 1 to 3, 1 is default(everything)\n"); + fprintf(stderr, "\t\t-T to print transitions\n"); + fprintf(stderr, "\t\t-e to print list of combinations of\n"); + fprintf(stderr, "\t\t\t [event,old_state] that produce protocol errors\n"); + fprintf(stderr, "\t\t-g include profiling code in driver\n"); + Exit(-1); +} + +openfiles(proto) +register char *proto; +{ + register char *junk; + register int lenp = strlen(proto); + + IFDEBUG(b) + fprintf(OUT, "openfiles %s\n",proto); + ENDDEBUG + +#define HEADER Header +#define SOURCE Source +#define DOIT(X)\ + /* GAG */\ + junk = Malloc( 2 + lenp + strlen(X/**/_name) );\ + (void) sprintf(junk, "%s_", proto);\ + X/**/_name = strcat(junk, X/**/_name);\ + X = fopen(X/**/_name, "w");\ + if((X)==(FILE *)0)\ + { fprintf(stderr,"Open failed: %s\n", "X"); Exit(-1); }\ + fprintf(X, "/* %cHeader%c */\n",'$', '$' );\ + fprintf(X, "/* %cSource%c */\n",'$', '$' ); + + DOIT(eventfile_h); + + IFDEBUG(X) +#ifdef DEBUG + DOIT(astringfile); +#endif DEBUG + fprintf(astringfile, + "#ifndef _NFILE\n#include <stdio.h>\n#endif _NFILE\n" ); + ENDDEBUG + + DOIT(statevalfile); + DOIT(statefile); + DOIT(actfile); + fprintf(actfile, + "#ifndef lint\nstatic char *rcsid = \"$Header/**/$\";\n#endif lint\n"); + + if(pgoption) + putdriver(actfile, 15); + else + putdriver(actfile, 14); + + FakeFilename(actfile, Transfilename, lineno); + putdriver(actfile, 1); + FakeFilename(actfile, Transfilename, lineno); + putdriver(actfile, 12); + fprintf(actfile, "#include \"%s%s\"\n", kerneldirname, statevalfile_name); + FakeFilename(actfile, Transfilename, lineno); + putdriver(actfile, 2); + + initsets(eventfile_h, statefile); +} + +includecode(file, f) +FILE *file; +register char *f; +{ + register int count=1; + static char o='{'; + static char c='}'; + register char *g; + + IFDEBUG(a) + fprintf(stdout, "including: %s, f=0x%x", f,f); + ENDDEBUG + g = ++f; + while(count>0) { + if(*g == o) count++; + if(*g == c) count--; + g++; + } + *(--g) = '\0'; + IFDEBUG(a) + fprintf(stdout, "derived: %s", f); + ENDDEBUG + fprintf(file, "%s", f); + FakeFilename(file, Transfilename, lineno); +} + +putincludes() +{ + FakeFilename(actfile, Transfilename, lineno); + fprintf(actfile, "\n#include \"%s%s\"\n", kerneldirname, eventfile_h_name); + IFDEBUG(X) + if( !debug['K'] ) + fprintf(actfile, "\n#include \"%s\"\n", astringfile_name); + /* not in kernel mode */ + ENDDEBUG + FakeFilename(actfile, Transfilename, lineno); +} + +main(argc, argv) +int argc; +char *argv[]; +{ + register int i = 2; + extern char *strcpy(); + int start, finish; + extern int FirstEventAttribute; + extern int Nevents, Nstates; + + start = time(0); + if(argc < 2) { + usage(argv[0]); + } + IFDEBUG(a) + fprintf(stdout, "infile = %s\n",argv[1]); + ENDDEBUG + Transfilename = argv[1]; + infile = fopen(argv[1], "r"); + + if(argc > 2) while(i < argc) { + register int j=0; + char c; + char *name; + + if(argv[i][j] == '-') j++; + switch(c = argv[i][j]) { + + /* GROT */ + case 'A': + name = &argv[i][++j]; + actfile_name = Malloc( strlen(name)+4); + actfile_name = (char *)strcpy(actfile_name,name); +#ifdef LINT + name = +#endif LINT + strcat(actfile_name, ".c"); + fprintf(stdout, "debugging file is %s\n",actfile_name); + break; + case 'K': + debug[c]=1; + fprintf(OUT, "option %c file %s\n",c, &argv[i][j+1]); + (void) strcpy(kerneldirname,&argv[i][++j]); + break; + case 'X': + debug[c]=1; + name = &argv[i][++j]; + astringfile_name = Malloc( strlen(name)+4); + astringfile_name = (char *)strcpy(astringfile_name,name); +#ifdef LINT + name = +#endif LINT + strcat(astringfile_name, ".c"); + fprintf(OUT, "option %c, astringfile name %s\n",c, name); + break; + case 'E': + name = &argv[i][++j]; + eventfile_h_name = Malloc( strlen(name)+4); + eventfile_h_name = (char *)strcpy(eventfile_h_name,name); +#ifdef LINT + name = +#endif LINT + strcat(eventfile_h_name, ".h"); + fprintf(stdout, "event files is %s\n",eventfile_h_name); + break; + case 'I': + name = &argv[i][++j]; + statevalfile_name = Malloc( strlen(name)+4 ); + statevalfile_name = (char *)strcpy(statevalfile_name,name); +#ifdef LINT + name = +#endif LINT + strcat(statevalfile_name, ".init"); + fprintf(stdout, "state table initial values file is %s\n",statevalfile_name); + break; + case 'S': + name = &argv[i][++j]; + statefile_name = Malloc( strlen(name)+4); + statefile_name = (char *)strcpy(statefile_name,name); +#ifdef LINT + name = +#endif LINT + strcat(statefile_name, ".h"); + fprintf(stdout, "state file is %s\n",statefile_name); + break; + /* END GROT */ + case '1': + case '2': + case '3': + debug['X']= (int)argv[i][j] - (int) '0'; + fprintf(OUT, "value of debug['X'] is 0x%x,%d\n", debug['X'], + debug['X']); + break; + case 'D': + while( c = argv[i][++j] ) { + if(c == 'X') { + fprintf(OUT, "debugging on"); + if(debug['X']) fprintf(OUT, + " - overrides any -%d flags used\n", debug['X']); + } + debug[c]=1; + fprintf(OUT, "debug %c\n",c); + } + break; + case 'g': + pgoption = 1; + fprintf(stdout, "Profiling\n"); + break; + case 'e': + print_protoerrs = 1; + fprintf(stdout, "Protocol error table:\n"); + break; + + case 'T': + print_trans = 1; + fprintf(stdout, "Transitions:\n"); + break; + default: + usage(argv[0]); + break; + } + i++; + } + if(kerneldirname[0]) { + char *c; +#ifdef notdef + if(debug['X']) { + fprintf(OUT, "Option K overrides option X\n"); + debug['X'] = 0; + } +#endif notdef + if(strlen(kerneldirname)<1) { + fprintf(OUT, "K option: dir name too short!\n"); + exit(-1); + } + /* add ../name/ */ + c = (char *) Malloc(strlen(kerneldirname)+6) ; + if(c <= (char *)0) { + fprintf(OUT, "Cannot allocate %d bytes for kerneldirname\n", + strlen(kerneldirname + 6) ); + fprintf(OUT, "kerneldirname is %s\n", kerneldirname ); + exit(-1); + } + *c = '.'; + *(c+1) = '.'; + *(c+2) = '/'; + (void) strcat(c, kerneldirname); + (void) strcat(c, "/\0"); + strcpy(kerneldirname, c); + } + + init_alloc(); + + (void) llparse(); + + /* {{ */ + if( !FirstEventAttribute ) + fprintf(eventfile_h, "\t}ev_union;\n"); + fprintf(eventfile_h, "};/* end struct event */\n"); + fprintf(eventfile_h, "\n#define %s_NEVENTS 0x%x\n", protocol, Nevents); + fprintf(eventfile_h, + "\n#define ATTR(X)ev_union.%s/**/X/**/\n",EV_PREFIX); + (void) fclose(eventfile_h); + + /* {{ */ fprintf(actfile, "\t}\nreturn 0;\n}\n"); /* end switch; end action() */ + dump_predtable(actfile); + + putdriver(actfile, 3); + IFDEBUG(X) + if(!debug['K']) + putdriver(actfile, 4); + ENDDEBUG + putdriver(actfile, 6); + IFDEBUG(X) + /* + putdriver(actfile, 10); + */ + if(debug['K']) { + putdriver(actfile, 11); + } else { + switch(debug['X']) { + case 1: + default: + putdriver(actfile, 7); + break; + case 2: + putdriver(actfile, 13); + break; + case 3: + break; + } + } + ENDDEBUG + putdriver(actfile, 8); + (void) fclose(actfile); + IFDEBUG(X) + /* { */ + fprintf(astringfile, "};\n"); + (void) fclose(astringfile); + ENDDEBUG + + (void) fclose(statevalfile); + + fprintf(statefile, "\n#define %s_NSTATES 0x%x\n", protocol, Nstates); + (void) fclose(statefile); + + finish = time(0); + fprintf(stdout, "%d seconds\n", finish - start); + if( print_protoerrs ) + printprotoerrs(); +} + +int transno = 0; + +Exit(n) +{ + fprintf(stderr, "Error at line %d\n",lineno); + if(transno) fprintf(stderr, "Transition number %d\n",transno); + (void) fflush(stdout); + (void) fflush(statefile); + (void) fflush(eventfile_h); + (void) fflush(actfile); + exit(n); +} + +syntax() +{ + static char *synt[] = { + "*PROTOCOL <string>\n", + "*PCB <string> <optional: SYNONYM synonymstring>\n", + "<optional: *INCLUDE {\n<C source>\n} >\n", + "*STATES <string>\n", + "*EVENTS <string>\n", + "*TRANSITIONS <string>\n", + }; +} + +FakeFilename(outfile, name, l) +FILE *outfile; +char *name; +int l; +{ + /* + doesn't work + fprintf(outfile, "\n\n\n\n# line %d \"%s\"\n", l, name); + */ +} diff --git a/sys/netiso/xebec/main.h b/sys/netiso/xebec/main.h new file mode 100644 index 0000000..cb5bd74 --- /dev/null +++ b/sys/netiso/xebec/main.h @@ -0,0 +1,32 @@ +/* $Header: main.h,v 2.1 88/09/19 12:56:24 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/main.h,v $ */ + +#define TRUE 1 +#define FALSE 0 +#define LINELEN 2350 + /* approx limit on token size for C compiler + * which matters for the purpose of debugging (astring.c...) + */ + +#define MSIZE 4000 +#define DEBUGFILE "astring.c" +#define ACTFILE "driver.c" +#define EVENTFILE_H "events.h" +#define STATEFILE "states.h" +#define STATEVALFILE "states.init" + +#define EV_PREFIX "EV_" +#define ST_PREFIX "ST_" + +#define PCBNAME "_PCB_" + +extern char kerneldirname[]; +extern char protocol[]; +extern char *synonyms[]; +#define EVENT_SYN 0 +#define PCB_SYN 1 + +extern int transno; +extern int print_trans; +extern char *stash(); + diff --git a/sys/netiso/xebec/malloc.c b/sys/netiso/xebec/malloc.c new file mode 100644 index 0000000..5cdfc14 --- /dev/null +++ b/sys/netiso/xebec/malloc.c @@ -0,0 +1,136 @@ +/* $Header: malloc.c,v 2.2 88/09/19 12:55:18 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/malloc.c,v $ */ +/* + * This code is such a kludge that I don't want to put my name on it. + * It was a ridiculously fast hack and needs rewriting. + * However it does work... + */ + +/* + * a simple malloc + * it might be brain-damaged but for the purposes of xebec + * it's a whole lot faster than the c library malloc + */ + +#include <stdio.h> +#include "malloc.h" +#include "debug.h" +#define CHUNKSIZE 4096*2 + +static char *hiwat, *highend; +int bytesmalloced=0; +int byteswasted = 0; + + +init_alloc() +{ +#ifdef LINT + hiwat = 0; + highend = 0; +#else LINT + extern char *sbrk(); + + hiwat = (char *) sbrk(0); + hiwat = (char *)((unsigned)(hiwat + 3) & ~0x3); + highend = hiwat; +#endif LINT +} + +HIWAT(s) +char *s; +{ + IFDEBUG(M) + fprintf(stdout, "HIWAT 0x%x %s\n", hiwat,s); + fflush(stdout); + ENDDEBUG +} + +#define MIN(x,y) ((x<y)?x:y) + +char *Malloc(x) +int x; +{ + char *c; + extern char *sbrk(); + static int firsttime=1; + int total = x; + int first_iter = 1; + char *returnvalue; + + IFDEBUG(N) + fprintf(stdout, "Malloc 0x%x, %d, bytesmalloced %d\n", + total,total, bytesmalloced); + fflush(stdout); + ENDDEBUG + IFDEBUG(M) + fprintf(stdout, "Malloc 0x%x, %d, hiwat 0x%x\n", + total,total, hiwat); + fflush(stdout); + ENDDEBUG + if(firsttime) { + hiwat = sbrk(0); + if(((unsigned)(hiwat) & 0x3)) { + bytesmalloced = 4 - (int) ((unsigned)(hiwat) & 0x3); + hiwat = sbrk( bytesmalloced ); + } else + bytesmalloced = 0; + firsttime = 0; + highend = hiwat; + } + while( total ) { + x = MIN(CHUNKSIZE, total); + if(total != x) { + IFDEBUG(N) + fprintf(stdout, "BIG Malloc tot %d, x %d, left %d net %d\n", + total,x, total-x, bytesmalloced); + fflush(stdout); + ENDDEBUG + } + if ( (hiwat + x) > highend) { + c = sbrk(CHUNKSIZE); + IFDEBUG(M) + fprintf(stdout, "hiwat 0x%x, x 0x%x, highend 0x%x, c 0x%x\n", + hiwat, x, highend, c); + fflush(stdout); + ENDDEBUG + if( c == (char *) -1 ) { + fprintf(stderr, "Ran out of memory!\n"); + Exit(-1); + } + if(first_iter) { + returnvalue = c; + first_iter = 0; + } + bytesmalloced += CHUNKSIZE; + IFDEBUG(m) + if (highend != c) { + fprintf(OUT, "warning: %d wasted bytes!\n", highend - hiwat); + fprintf(OUT, " chunksize 0x%x, x 0x%x \n", CHUNKSIZE, x); + } + ENDDEBUG + highend = c + CHUNKSIZE; + hiwat = c; + } + c = hiwat; + if(first_iter) { + returnvalue = c; + first_iter = 0; + } + hiwat += x; + total -= x; + } + if((unsigned)hiwat & 0x3) { + byteswasted += (int)((unsigned)(hiwat) & 0x3); + hiwat = (char *)((unsigned)(hiwat + 3) & ~0x3); + } + IFDEBUG(M) + fprintf(stdout, "Malloc = 0x%x, bytesm 0x%x, wasted 0x%x, hiwat 0x%x\n", + returnvalue, bytesmalloced, byteswasted, hiwat); + ENDDEBUG + IFDEBUG(N) + fprintf(stdout, "Malloc returns 0x%x, sbrk(0) 0x%x\n", returnvalue, sbrk(0)); + fflush(stdout); + ENDDEBUG + return(returnvalue); +} + diff --git a/sys/netiso/xebec/malloc.h b/sys/netiso/xebec/malloc.h new file mode 100644 index 0000000..53d865b --- /dev/null +++ b/sys/netiso/xebec/malloc.h @@ -0,0 +1,4 @@ +/* $Header: malloc.h,v 2.1 88/09/19 12:56:27 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/malloc.h,v $ */ + +char *Malloc(); diff --git a/sys/netiso/xebec/procs.c b/sys/netiso/xebec/procs.c new file mode 100644 index 0000000..49d862a --- /dev/null +++ b/sys/netiso/xebec/procs.c @@ -0,0 +1,437 @@ +/* $Header: procs.c,v 2.3 88/09/19 12:55:22 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/procs.c,v $ */ +/* + * This code is such a kludge that I don't want to put my name on it. + * It was a ridiculously fast hack and needs rewriting. + * However it does work... + */ + +#include <stdio.h> +#include <strings.h> +#include "malloc.h" +#include "main.h" +#include "debug.h" +#include "sets.h" +#include "procs.h" + +struct Predicate { + int p_index; + int p_transno; + char *p_str; + struct Predicate *p_next; +}; + +struct Stateent { + int s_index; + int s_newstate; + int s_action; + struct Stateent *s_next; +}; + +struct Object *SameState = (struct Object *)-1; +int Index = 0; +int Nstates = 0; +int Nevents = 0; +struct Predicate **Predlist; +struct Stateent **Statelist; +extern FILE *astringfile; + +end_events() { + int size, part; + char *addr; + + IFDEBUG(X) + /* finish estring[], start astring[] */ + if(debug['X'] < 2 ) + fprintf(astringfile, "};\n\nchar *%s_astring[] = {\n\"NULLACTION\",\n", + protocol); + ENDDEBUG + /* NOSTRICT */ + Statelist = + (struct Stateent **) Malloc((Nstates+1) * sizeof(struct Statent *)); + /* NOSTRICT */ + Predlist = + (struct Predicate **) + Malloc ( (((Nevents)<<Eventshift)+Nstates)*sizeof(struct Predicate *) ); + + size = (((Nevents)<<Eventshift)+Nstates)*sizeof(struct Predicate *) ; + addr = (char *)Predlist; + IFDEBUG(N) + fprintf(OUT, "Predlist at 0x%x, sbrk 0x%x bzero size %d at addr 0x%x\n", + Predlist, sbrk(0), size, addr); + ENDDEBUG +#define BZSIZE 8192 + while(size) { + part = size>BZSIZE?BZSIZE:size; + IFDEBUG(N) + fprintf(OUT, "bzero addr 0x%x part %d size %d\n",addr, part, size); + ENDDEBUG + bzero(addr, part); + IFDEBUG(N) + fprintf(OUT, "after bzero addr 0x%x part %d size %d\n",addr, part, size); + ENDDEBUG + addr += part; + size -= part; + + } + IFDEBUG(N) + fprintf(OUT, "endevents..done \n"); + ENDDEBUG +} + +int acttable(f,actstring) +char *actstring; +FILE *f; +{ + static Actindex = 0; + extern FILE *astringfile; + extern int pgoption; + + IFDEBUG(a) + fprintf(OUT,"acttable()\n"); + ENDDEBUG + fprintf(f, "case 0x%x: \n", ++Actindex); + + if(pgoption) { + fprintf(f, "asm(\" # dummy statement\");\n"); + fprintf(f, "asm(\"_Xebec_action_%x: \");\n", Actindex ); + fprintf(f, "asm(\".data\");\n"); + fprintf(f, "asm(\".globl _Xebec_action_%x# X profiling\");\n", + Actindex ); + fprintf(f, "asm(\".long 0 # X profiling\");\n"); + fprintf(f, "asm(\".text # X profiling\");\n"); + fprintf(f, "asm(\"cas r0,r15,r0 # X profiling\");\n"); + fprintf(f, "asm(\"bali r15,mcount # X profiling\");\n"); + } + + fprintf(f, "\t\t%s\n\t\t break;\n", actstring); + IFDEBUG(X) + if(debug['X']<2) { + register int len = 0; + fputc('"',astringfile); + while(*actstring) { + if( *actstring == '\n' ) { + fputc('\\', astringfile); + len++; + fputc('n', astringfile); + } else if (*actstring == '\\') { + fputc('\\', astringfile); + len ++; + fputc('\\', astringfile); + } else if (*actstring == '\"') { + fputc('\\', astringfile); + len ++; + fputc('\"', astringfile); + } else fputc(*actstring, astringfile); + actstring++; + len++; + } + fprintf(astringfile,"\",\n"); + if (len > LINELEN) { + fprintf(stderr, "Action too long: %d\n",len); Exit(-1); + } + } + ENDDEBUG + + return(Actindex); +} + +static int Npred=0, Ndefpred=0, Ntrans=0, Ndefevent=0, Nnulla=0; + +statetable(string, oldstate, newstate, action, event) +char *string; +int action; +struct Object *oldstate, *newstate, *event; +{ + register int different; + + IFDEBUG(a) + fprintf(OUT,"statetable(0x%x, 0x%x,0x%x, 0x%x)\n", + string, oldstate, newstate, action); + fprintf(OUT,"statetable(%s, %s,%s, 0x%x)\n", + string, oldstate->obj_name, newstate->obj_name, action); + ENDDEBUG + + if( !action) Nnulla++; + if( newstate->obj_kind == OBJ_SET) { + fprintf(stderr, "Newstate cannot be a set\n"); + Exit(-1); + } + different = (newstate != SameState); + + (void) predtable( oldstate, event, string, + action, (newstate->obj_number) * different ); + IFDEBUG(a) + fprintf(OUT,"EXIT statetable\n"); + ENDDEBUG +} + +stateentry(index, oldstate, newstate, action) +int index, action; +int oldstate, newstate; +{ + extern FILE *statevalfile; + + IFDEBUG(a) + fprintf(OUT,"stateentry(0x%x,0x%x,0x%x,0x%x) Statelist@0x%x, val 0x%x\n", + index, oldstate, newstate,action, &Statelist, Statelist); + ENDDEBUG + + + fprintf(statevalfile, "{0x%x,0x%x},\n", newstate, action); +} + +int predtable(os, oe, str, action, newstate) +struct Object *os, *oe; +char *str; +int action, newstate; +{ + register struct Predicate *p, **q; + register int event, state; + register struct Object *e, *s; + struct Object *firste; + + if (oe == (struct Object *)0 ) { + Ndefevent ++; + fprintf(stderr, "DEFAULT EVENTS aren't implemented; trans ignored\n"); + return; + } + Ntrans++; + IFDEBUG(g) + fprintf(stdout, + "PREDTAB: s %5s; e %5s\n", os->obj_kind==OBJ_SET?"SET":"item", + oe->obj_kind==OBJ_SET?"SET":"item"); + ENDDEBUG + if (os->obj_kind == OBJ_SET) s = os->obj_members; + else s = os; + if (oe->obj_kind == OBJ_SET) firste = oe->obj_members; + else firste = oe; + if(newstate) { + fprintf(statevalfile, "{0x%x,0x%x},\n",newstate, action); + Index++; + } + while (s) { + if( !newstate ) { /* !newstate --> SAME */ + /* i.e., use old obj_number */ + fprintf(statevalfile, "{0x%x,0x%x},\n",s->obj_number, action); + Index++; + } + e = firste; + while (e) { + event = e->obj_number; state = s->obj_number; + IFDEBUG(g) + fprintf(stdout,"pred table event=0x%x, state 0x%x\n", + event, state); + fflush(stdout); + ENDDEBUG + if( !str /* DEFAULT PREDICATE */) { + Ndefpred++; + IFDEBUG(g) + fprintf(stdout, + "DEFAULT pred state 0x%x, event 0x%x, Index 0x%x\n", + state, event, Index); + fflush(stdout); + ENDDEBUG + } else + Npred++; + /* put at END of list */ +#ifndef LINT + IFDEBUG(g) + fprintf(stdout, + "predicate for event 0x%x, state 0x%x is 0x%x, %s\n", + event, state, Index, str); + fflush(stdout); + ENDDEBUG +#endif LINT + for( ((q = &Predlist[(event<<Eventshift)+state]), + (p = Predlist[(event<<Eventshift)+state])); + p ; p = p->p_next ) { + q = &p->p_next; + } + + p = (struct Predicate *)Malloc(sizeof(struct Predicate)); + p->p_next = (struct Predicate *)0; + p->p_str = str; + p->p_index = Index; + p->p_transno = transno; + *q = p; + + IFDEBUG(g) + fprintf(stdout, + "predtable index 0x%x, transno %d, E 0x%x, S 0x%x\n", + Index, transno, e, s); + ENDDEBUG + + e = e->obj_members; + } + s = s->obj_members; + } + return Index ; +} + +printprotoerrs() +{ + register int e,s; + + fprintf(stderr, "[ Event, State ] without any transitions :\n"); + for(e = 0; e < Nevents; e++) { + fprintf(stderr, "Event 0x%x: states ", e); + for(s = 0; s < Nstates; s++) { + if( Predlist[(e<<Eventshift)+s] == 0 ) + fprintf(stderr, "0x%x ", s); + } + fprintf(stderr, "\n"); + } +} + +#ifndef LINT +dump_predtable(f) +FILE *f; +{ + struct Predicate *p; + register int e,s, hadapred; + int defaultindex; + int defaultItrans; + extern int bytesmalloced; + extern int byteswasted; + +#ifdef notdef + fprintf(stdout, + " Xebec used %8d bytes of storage, wasted %8d bytes\n", + bytesmalloced, byteswasted); +#endif notdef + fprintf(stdout, + " %8d states\n %8d events\n %8d transitions\n", + Nstates, Nevents, Ntrans); + fprintf(stdout, + " %8d predicates\n %8d default predicates used\n", + Npred, Ndefpred); + fprintf(stdout, + " %8d null actions\n", + Nnulla); + + putdriver(f, 5); + for(e = 0; e < Nevents; e++) { for(s = 0; s < Nstates; s++) { + p = Predlist[(e<<Eventshift)+s]; + hadapred=0; + defaultindex=0; + defaultItrans=0; + if(p) { + IFDEBUG(d) + fflush(f); + ENDDEBUG + while(p) { + if(p->p_str) { + if(!hadapred) + fprintf(f, "case 0x%x:\n\t", (e<<Eventshift) + s); + hadapred = 1; + fprintf(f, "if %s return 0x%x;\n\t else ", + p->p_str, p->p_index); + } else { + if(defaultindex) { + fprintf(stderr, +"\nConflict between transitions %d and %d: duplicate default \n", + p->p_transno, defaultItrans); + Exit(-1); + } + defaultindex = p->p_index; + defaultItrans = p->p_transno; + } + p = p->p_next; + } + if( hadapred) { + fprintf(f, "return 0x%x;\n", defaultindex); + } + IFDEBUG(d) + fflush(f); + ENDDEBUG + } + IFDEBUG(g) + fprintf(stdout, + "loop: e 0x%x s 0x%x hadapred 0x%x dindex 0x%x for trans 0x%x\n", + e, s, hadapred, defaultindex, defaultItrans); + ENDDEBUG + if ( hadapred ) { + /* put a -1 in the array - Predlist is temporary storage */ + Predlist[(e<<Eventshift)+s] = (struct Predicate *)(-1); + } else { + /* put defaultindex in the array */ + /* if defaultindex is zero, then the driver will + * cause an erroraction (same as if no default + * were given and none of the predicates were true; + * also same as if no preds or defaults were given + * for this combo) + */ + Predlist[(e<<Eventshift)+s] = (struct Predicate *)(defaultindex); + } + } } + fprintf(f, "default: return 0;\n} /* end switch */\n"); +#ifdef notdef + fprintf(f, "/*NOTREACHED*/return 0;\n} /* _Xebec_index() */\n"); +#else notdef + fprintf(f, "} /* _Xebec_index() */\n"); +#endif notdef + fprintf(f, "static int inx[%d][%d] = { {", Nevents+1,Nstates); + for(s = 0; s< Nstates; s++) fprintf(f, "0,"); /* event 0 */ + fprintf(f, "},\n"); + + for(e = 0; e < Nevents; e++) { + fprintf(f, " {"); + for(s = 0; s < Nstates; s++) { + register struct Predicate *xyz = Predlist[(e<<Eventshift)+s]; + /* this kludge is to avoid a lint msg. concerning + * loss of bits + */ + if (xyz == (struct Predicate *)(-1)) + fprintf(f, "-1,"); + else + fprintf(f, "0x%x,", Predlist[(e<<Eventshift)+s]); + } + fprintf(f, " },\n"); + } + fprintf(f, "};"); +} +#endif LINT + +char * +stash(buf) +char *buf; +{ + register int len; + register char *c; + + /* grot */ + len = strlen(buf); + c = Malloc(len+1); +#ifdef LINT + c = +#endif LINT + strcpy(c, buf); + + IFDEBUG(z) + fprintf(stdout,"stash %s at 0x%x\n", c,c); + ENDDEBUG + return(c); +} + +#ifdef notdef +dump_pentry(event,state) +int event,state; +{ + register struct Predicate *p, **q; + + for( + ((q = &Predlist[(event<<Eventshift) +state]), + (p = Predlist[(event<<Eventshift) + state])); + p!= (struct Predicate *)0 ; p = p->p_next ) { +#ifndef LINT + IFDEBUG(a) + fprintf(OUT, + "dump_pentry for event 0x%x, state 0x%x is 0x%x\n", + event, state, p); + ENDDEBUG +#endif LINT + q = &p->p_next; + } +} +#endif notdef diff --git a/sys/netiso/xebec/procs.h b/sys/netiso/xebec/procs.h new file mode 100644 index 0000000..e41ae75 --- /dev/null +++ b/sys/netiso/xebec/procs.h @@ -0,0 +1,5 @@ +/* $Header: procs.h,v 2.1 88/09/19 12:56:30 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/procs.h,v $ */ + +extern char *stash(); +extern struct Object *SameState; diff --git a/sys/netiso/xebec/putdriver.c b/sys/netiso/xebec/putdriver.c new file mode 100644 index 0000000..996ac64 --- /dev/null +++ b/sys/netiso/xebec/putdriver.c @@ -0,0 +1,244 @@ +/* $Header: putdriver.c,v 2.2 88/09/19 12:55:27 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/putdriver.c,v $ */ + +/* + * This code is such a kludge that I don't want to put my name on it. + * It was a ridiculously fast hack and needs rewriting. + * However it does work... + */ + +/* The original idea was to put all the driver code + * in one place so it would be easy to modify + * but as hacks got thrown in it got worse and worse... + * It's to the point where a user would be better off + * writing his own driver and xebec should JUST produce + * the tables. + */ + +#include <stdio.h> +#include "main.h" +#include "debug.h" + +extern char protocol[]; +char Eventshiftstring[10]; +static char statename[] = {'_', 's', 't', 'a', 't', 'e', 0 }; + +static char *strings[] = { + +#define PART1 { 0,3 } + + "\n#include \"", + kerneldirname, + protocol, + "_states.h\"", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART12 { 10,12 } + "\n\nstatic struct act_ent {\n", + "\tint a_newstate;\n\tint a_action;\n", + "} statetable[] = { {0,0},\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART2 { 20,20 } + "};\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART3 { 30,41 } + "\n", + protocol, + "_driver(p, e)\nregister ", + protocol, + PCBNAME, + " *p;\nregister struct ", + protocol, + "_event *e;\n", + "{\n", + "\tregister int index, error=0;\n", + "\tstruct act_ent *a;\n", + "\tstatic struct act_ent erroraction = {0,-1};\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART4 { 50,54 } + + "\textern int ", + protocol, + "_debug;\n\textern FILE *", + protocol, + "_astringfile;\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART6 { 60, 65 } + "\n\tindex = inx[1 + e->ev_number][p->", + protocol, + statename, + "];\n\tif(index<0) index=_Xebec_index(e, p);\n", + "\tif (index==0) {\n\t\ta = &erroraction;\n", + "\t} else\n\t\ta = &statetable[index];\n\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART7 {70, 77 } + "\tif(", + protocol, + "_debug) fprintf(", + protocol, + "_astringfile, \"%15s <-- %15s [%15s] \\n\\t%s\\n\",\n", + "\t\tsstring[a->a_newstate], sstring[p->", + protocol, + "_state], estring[e->ev_number], astring[a->a_action]);\n\n", + (char *)0, + (char *)0, + +#define PART8 { 80, 84 } + "\tif(a->a_action)\n", + "\t\terror = _Xebec_action( a->a_action, e, p );\n", + "\tif(error==0)\n\tp->", + protocol, + "_state = a->a_newstate;\n\treturn error;\n}\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART9 { 90, 99 } + "\n_XEBEC_PG int _Xebec_action(a,e,p)\nint a;\nstruct ", + protocol, + "_event *e;\n", + protocol, + PCBNAME, + " *p;\n{\n", + "switch(a) {\n", + "case -1: return ", + protocol, + "_protocol_error(e,p);\n", + (char *)0, + +#define PART10 { 101, 105 } + "\tif(", + protocol, + "_debug) fprintf(", + protocol, + "_astringfile, \"index 0x%5x\\n\", index);\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART5 { 110, 121 } + "\n_XEBEC_PG int\n_Xebec_index( e,p )\n", + "\tstruct ", + protocol, + "_event *e;\n\t", + protocol, + PCBNAME, + " *p;\n{\nswitch( (e->ev_number<<", + Eventshiftstring, + ")+(p->", + protocol, + statename, + ") ) {\n", + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + (char *)0, + +#define PART11 {130, 137 } + "\tIFTRACE(D_DRIVER)\n", + "\t", + protocol, + "trace(DRIVERTRACE,", + "\t\ta->a_newstate, p->", + protocol, + "_state, e->ev_number, a->a_action, 0);\n\n", + "\tENDTRACE\n", + (char *)0, + (char *)0, + +#define PART13 {140, 147 } + "\tif(", + protocol, + "_debug) fprintf(", + protocol, + "_astringfile, \"%15s <-- %15s [%15s] \\n\",\n", + "\t\tsstring[a->a_newstate], sstring[p->", + protocol, + "_state], estring[e->ev_number]);\n\n", + (char *)0, + (char *)0, + +#define PART14 { 150,150 } + "#define _XEBEC_PG static\n", + +#define PART15 { 151,151 } + "#define _XEBEC_PG \n", + +}; + +static struct { int start; int finish; } parts[] = { + { 0,0 }, + PART1, + PART2, + PART3, + PART4, + PART5, + PART6, + PART7, + PART8, + PART9, + PART10, + PART11, + PART12, + PART13, + PART14, + PART15, +}; + +putdriver(f, x) +FILE *f; +int x; +{ + register int i; + + for( i = parts[x].start; i<= parts[x].finish; i++) + fprintf(f, "%s", strings[i]); + IFDEBUG(d) + fflush(f); + ENDDEBUG +} diff --git a/sys/netiso/xebec/sets.c b/sys/netiso/xebec/sets.c new file mode 100644 index 0000000..3bb74ed --- /dev/null +++ b/sys/netiso/xebec/sets.c @@ -0,0 +1,472 @@ +/* $Header: sets.c,v 2.3 88/09/19 12:55:30 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/sets.c,v $ */ +/* + * This code is such a kludge that I don't want to put my name on it. + * It was a ridiculously fast hack and needs rewriting. + * However it does work... + */ +#include "main.h" +#include "malloc.h" +#include "sets.h" +#include "debug.h" +#include <stdio.h> + +struct Object *CurrentEvent = (struct Object *)0; +struct Object *Objtree; +struct Object dummy; +/* + * define a set w/ type and name + * return a set number + */ +#undef NULL +#define NULL (struct Object *)0 + +static FILE *Sfile, *Efile; +extern FILE *astringfile; +char *Noname = "Unnamed set\0"; + +initsets(f,s) +FILE *f, *s; +{ + static char errorstring[20]; + extern struct Object *SameState; + Efile = f; + Sfile = s; + + IFDEBUG(X) + fprintf(astringfile, "char *%s_sstring[] = {\n", protocol); + ENDDEBUG + sprintf(errorstring, "%sERROR\0", ST_PREFIX); + defineitem(STATESET, errorstring, (char *)0); /* state 0 */ + SameState = (struct Object *) Malloc( sizeof (struct Object) ); + SameState->obj_kind = OBJ_ITEM; + SameState->obj_type = STATESET; + SameState->obj_name = "SAME"; + SameState->obj_struc = (char *)0; + SameState->obj_number = 0; + SameState->obj_members = (struct Object *)0; + SameState->obj_left = (struct Object *)0; + SameState->obj_right = (struct Object *)0; + SameState->obj_parent = (struct Object *)0; +} + +/* + * get a set based on its type and name + * returns address of an Object, may be set or item + */ + +struct Object *lookup(type, name) +unsigned char type; +char *name; +{ + register struct Object *p = Objtree; + int val = 1 ; + + IFDEBUG(o) + fprintf(stdout,"lookup 0x%x,%s \n", + type, name); + ENDDEBUG + + while( p && val ) { + IFDEBUG(o) + fprintf(OUT, "lookup strcmp 0x%x,%s, 0x%x,%s\n", + name, name, OBJ_NAME(p), OBJ_NAME(p)); + ENDDEBUG + if( p->obj_name == (char *)0 ) { + fprintf(stderr, "Unnamed set in table!\n"); + Exit(-1); + } + val = (int) strcmp(name, OBJ_NAME(p)); + if(val < 0) { + /* left */ + p = p->obj_left; + } else if (val > 0) { + /* right */ + p = p->obj_right; + } + } + if( p && ( p->obj_type != type)) { + fprintf(stdout, "lookup(0x%x,%s) found wrong obj type 0x%x\n", + type,name, p->obj_type); + p = NULL; + } + IFDEBUG(o) + fprintf(stdout,"lookup 0x%x,%s returning 0x%x\n",type, name, p); + ENDDEBUG + return(p); +} + +static int states_done = 0; + +end_states(f) +FILE *f; +{ + register unsigned n = Nstates; + register int i; + extern char Eventshiftstring[]; + + states_done = 1; + + for( i = 0; ;i++) { + if( (n >>= 1) <= 0 ) break; + } + Eventshift = i+1; + IFDEBUG(d) + fprintf(OUT, "Eventshift=%d\n", Eventshift); + ENDDEBUG + sprintf(Eventshiftstring, "%d\0",Eventshift); + fprintf(f, "struct %s_event {\n\tint ev_number;\n", &protocol[0]); + IFDEBUG(X) + /* finish sstring[] & start estring[] */ + fprintf(astringfile, + "};\n\nchar *%s_estring[] = {\n", protocol); + ENDDEBUG +} + +int FirstEventAttribute = 1; + +static +insert(o) +struct Object *o; +{ + struct Object *p = Objtree; + struct Object **q = &Objtree; + int val=1; + + + if (o->obj_name == (char *)0) { + fprintf(stderr, "Internal Error: inserting unnamed object\n"); + Exit(-1); + } + if( o->obj_type == STATESET) { + if( states_done ) { + fprintf(stderr, "No states may be defined after *TRANSITIONS\n"); + Exit(-1); + } + o->obj_number = Nstates++ ; + if(Nstates > MAXSTATES) { + fprintf(stderr, "Too many states\n"); + Exit(-1); + } + fprintf(Sfile, "#define %s 0x%x\n", o->obj_name, o->obj_number); + IFDEBUG(X) + fprintf(astringfile, "\"%s(0x%x)\",\n", o->obj_name, o->obj_number); + ENDDEBUG + } else { + /* EVENTSET */ + if( ! states_done ) { + fprintf(stderr, "states must precede events\n"); + Exit(-1); + } + o->obj_number = Nevents++ ; + if(Nevents > MAXEVENTS) { + fprintf(stderr, "Too many events\n"); + Exit(-1); + } + if(o->obj_struc) { + if( FirstEventAttribute ) { + fprintf(Efile, "\n\tunion{\n"); /*} */ + FirstEventAttribute = 0; + } + fprintf(Efile, + "struct %s %s%s;\n\n", o->obj_struc, EV_PREFIX, o->obj_name); + } + fprintf(Efile, "#define %s 0x%x\n", o->obj_name, o->obj_number); + IFDEBUG(X) + fprintf(astringfile, "\"%s(0x%x)\",\n", o->obj_name, o->obj_number); + ENDDEBUG + } + IFDEBUG(o) + fprintf(OUT, "insert(%s)\n", OBJ_NAME(o) ); + if(o->obj_right != NULL) { + fprintf(OUT, "insert: unclean Object right\n"); + exit(-1); + } + if(o->obj_left != NULL) { + fprintf(OUT, "insert: unclean Object left\n"); + exit(-1); + } + fflush(OUT); + ENDDEBUG + + while( val ) { + if(p == NULL) { + *q = o; + o->obj_parent = (struct Object *)q; + break; + } + if(!(val = strcmp(o->obj_name, p->obj_name)) ) { + /* equal */ + fprintf(stderr, "re-inserting %s\n",o->obj_name); + exit(-1); + } + if(val < 0) { + /* left */ + q = &p->obj_left; + p = p->obj_left; + } else { + /* right */ + q = &p->obj_right; + p = p->obj_right; + } + } + IFDEBUG(a) + dumptree(Objtree,0); + ENDDEBUG +} + +delete(o) +struct Object *o; +{ + register struct Object *p = o->obj_right; + register struct Object *q; + register struct Object *newparent; + register struct Object **np_childlink; + + IFDEBUG(T) + fprintf(stdout, "delete(0x%x)\n", o); + dumptree(Objtree,0); + ENDDEBUG + + /* q <== lowest valued node of the right subtree */ + while( p ) { + q = p; + p = p->obj_left; + } + + if (o->obj_parent == (struct Object *)&Objtree) { + newparent = (struct Object *)&Objtree; + np_childlink = (struct Object **)&Objtree; + } else if(o->obj_parent->obj_left == o) { + newparent = o->obj_parent; + np_childlink = &(o->obj_parent->obj_left); + } else { + newparent = o->obj_parent; + np_childlink = &(o->obj_parent->obj_right); + } + IFDEBUG(T) + fprintf(OUT, "newparent=0x%x\n"); + ENDDEBUG + + if (q) { /* q gets the left, parent gets the right */ + IFDEBUG(T) + fprintf(OUT, "delete: q null\n"); + ENDDEBUG + q->obj_left = p; + if(p) p->obj_parent = q; + p = o->obj_right; + } else { /* parent(instead of q) gets the left ; there is no right */ + IFDEBUG(T) + fprintf(OUT, "delete: q not null\n"); + ENDDEBUG + p = o->obj_left; + } + *np_childlink = p; + if(p) + p->obj_parent = newparent; + + IFDEBUG(T) + fprintf(OUT, "After deleting 0x%x\n",o); + dumptree(Objtree,0); + ENDDEBUG +} + +struct Object * +defineset(type, adr, keep) +unsigned char type; +char *adr; +int keep; +{ + struct Object *onew; + IFDEBUG(o) + printf("defineset(0x%x,%s, %s)\n", type , adr, keep?"KEEP":"NO_KEEP"); + ENDDEBUG + + onew = (struct Object *)Malloc(sizeof (struct Object)); + bzero(onew, sizeof(struct Object)); + onew->obj_name = adr; + onew->obj_kind = OBJ_SET; + onew->obj_type = type; + if(keep) + insert( onew ); + /* address already stashed before calling defineset */ + IFDEBUG(o) + printf("defineset(0x%x,%s) returning 0x%x\n", type , adr, onew); + dumptree(Objtree,0); + ENDDEBUG + return(onew); +} + +dumpit(o, s) +char *o; +char *s; +{ + register int i; + +IFDEBUG(o) + fprintf(OUT, "object 0x%x, %s\n",o, s); + for(i=0; i< sizeof(struct Object); i+=4) { + fprintf(OUT, "0x%x: 0x%x 0x%x 0x%x 0x%x\n", + *((int *)o), *o, *(o+1), *(o+2), *(o+3) ); + } +ENDDEBUG +} + +defineitem(type, adr, struc) +unsigned char type; +char *adr; +char *struc; +{ + struct Object *onew; + IFDEBUG(o) + printf("defineitem(0x%x, %s at 0x%x, %s)\n", type, adr, adr, struc); + ENDDEBUG + + if( onew = lookup( type, adr ) ) { + fprintf(stderr, + "Internal error at defineitem: trying to redefine obj type 0x%x, adr %s\n", + type, adr); + exit(-1); + } else { + onew = (struct Object *)Malloc(sizeof (struct Object)); + bzero(onew, sizeof(struct Object)); + onew->obj_name = stash(adr); + onew->obj_kind = OBJ_ITEM; + onew->obj_type = type; + onew->obj_struc = struc?stash(struc):struc; + insert( onew ); + } + IFDEBUG(o) + fprintf(OUT, "defineitem(0x%x, %s) returning 0x%x\n", type, adr, onew); + ENDDEBUG +} + +member(o, adr) +struct Object *o; +char *adr; +{ + struct Object *onew, *oold; + IFDEBUG(o) + printf("member(0x%x, %s)\n", o, adr); + ENDDEBUG + + oold = lookup( o->obj_type, adr ); + + onew = (struct Object *)Malloc(sizeof (struct Object)); + if( oold == NULL ) { + extern int lineno; + + fprintf(stderr, + "Warning at line %d: set definition of %s causes definition of\n", + lineno, OBJ_NAME(o)); + fprintf(stderr, "\t (previously undefined) member %s\n", adr); + bzero(onew, sizeof(struct Object)); + onew->obj_name = stash(adr); + onew->obj_kind = OBJ_ITEM; + onew->obj_type = o->obj_type; + onew->obj_members = NULL; + insert( onew ); + } else { + if(oold->obj_kind != OBJ_ITEM) { + fprintf(stderr, "Sets cannot be members of sets; %s\n", adr); + exit(-1); + } + bcopy(oold, onew, sizeof(struct Object)); + onew->obj_members = onew->obj_left = onew->obj_right = NULL; + } + onew->obj_members = o->obj_members; + o->obj_members = onew; +} + +struct Object *Lookup(type, name) +unsigned char type; +char *name; +{ + register struct Object *o = lookup(type,name); + + if(o == NULL) { + fprintf(stderr, "Trying to use undefined %s: %s\n", + type==STATESET?"state":"event", name); + Exit(-1); + } + return(o); +} + +AddCurrentEventName(x) +register char **x; +{ + register char *n = EV_PREFIX; ; + + if( CurrentEvent == (struct Object *)0 ) { + fprintf(stderr, "No event named! BARF!\n"); Exit(-1); + } + + if( ! CurrentEvent->obj_struc ) { + fprintf(stderr, "No attributes for current event!\n"); Exit(-1); + } + + /* add prefix first */ + while(*n) { + *(*x)++ = *n++; + } + + n = CurrentEvent->obj_name; + + while(*n) { + *(*x)++ = *n++; + } +} + +dumptree(o,i) + register struct Object *o; + int i; +{ + register int j; + + if(o == NULL) { + for(j=0; j<i; j++) + fputc(' ', stdout); + fprintf(stdout, "%3d NULL\n", i); + } else { + dumptree(o->obj_left, i+1); + for(j=0; j<i; j++) + fputc(' ', stdout); + fprintf(stdout, "%3d 0x%x: %s\n", i,o, OBJ_NAME(o)); + dumptree(o->obj_right, i+1); + } +} + +dump(c,a) +{ + register int x = 8; + int zero = 0; +#include <sys/signal.h> + + fprintf(stderr, "dump: c 0x%x, a 0x%x\n",c,a); + + x = x/zero; + kill(0, SIGQUIT); +} + +dump_trans( pred, oldstate, newstate, action, event ) +struct Object *oldstate, *newstate, *event; +char *pred, *action; +{ + extern int transno; + struct Object *o; + + fprintf(stdout, "\n%d: ", transno); +#define dumpit(x)\ + if((x)->obj_kind == OBJ_SET) {\ + o = (x)->obj_members; fprintf( stdout, "[ " );\ + while(o) { fprintf(stdout, "%s ", o->obj_name); o = o->obj_members; }\ + fprintf( stdout, " ] ");\ + } else { fprintf(stdout, "%s ", (x)->obj_name); } + + dumpit(newstate); + fprintf(stdout, " <== "); + dumpit(oldstate); + dumpit(event); + fprintf(stdout, "\n\t\t%s\n\t\t%s\n", pred?pred:"DEFAULT", + action); +} diff --git a/sys/netiso/xebec/sets.h b/sys/netiso/xebec/sets.h new file mode 100644 index 0000000..96eb791 --- /dev/null +++ b/sys/netiso/xebec/sets.h @@ -0,0 +1,36 @@ +/* $Header: sets.h,v 2.1 88/09/19 12:56:33 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/sets.h,v $ */ + +#define MAXEVENTS 200 +#define MAXSTATES 200 + +#define STATESET 10 +#define EVENTSET 5 + +#define OBJ_ITEM 2 +#define OBJ_SET 3 + +struct Object { + unsigned char obj_kind; + unsigned char obj_type; /* state or event */ + char *obj_name; + char *obj_struc; + int obj_number; + struct Object *obj_members; /* must be null for kind==item */ + /* for the tree */ + struct Object *obj_left; + struct Object *obj_right; + struct Object *obj_parent; +} ; + +extern char *Noname; + +#define OBJ_NAME(o) (((o)->obj_name)?(o)->obj_name:Noname) + +extern int Nevents, Nstates; +int Eventshift; +extern struct Object *CurrentEvent; + +extern struct Object *Lookup(); +extern struct Object *defineset(); + diff --git a/sys/netiso/xebec/test.trans b/sys/netiso/xebec/test.trans new file mode 100644 index 0000000..49db361 --- /dev/null +++ b/sys/netiso/xebec/test.trans @@ -0,0 +1,64 @@ +/* $Header: test.trans,v 0.2 88/09/19 12:58:29 nhall Exp $ + */ +*PROTOCOL test + +*INCLUDE + +{ +#include "test_def.h" +} + +*PCB test_pcbstruct SYNONYM P + +*STATES + +STATE_A +STATE_B +STATE_C +ALL_STATES = [STATE_A, STATE_B, STATE_C] + +*EVENTS { int ev_all; } SYNONYM E + +EV_1 { char *ev1_char; } +EV_2 { int ev2_int; char ev2_char; } +EV_3 +EV_4 { struct blah *ev4_blahptr; + unsigned int ev4_uint; + int ev4_int; + } + +*TRANSITIONS + +SAME <== [ STATE_A, STATE_B ] [ EV_1, EV_2, EV_3 ] + ( $E.ev_all > 0 ) + { + if( $P.test_state == STATE_A ) + printf("state is STATE_A\n"); + else + printf("state is STATE_B\n"); + printf("action first transition\n"); + } + +; +STATE_C <== [ STATE_A, STATE_B ] [ EV_1, EV_2, EV_3 ] + DEFAULT + { + printf("default - transition 2\n"); + MACRO1( $P.test_pcbfield ); + } +; + +STATE_C <== [ STATE_A, STATE_B ] EV_4 + ( $$.ev4_blahptr->blahfield & 0x1 ) + NULLACTION +; + +STATE_C <== ALL_STATES EV_4 + DEFAULT + { + printf("default - transition 4\n"); + printf("pcb is 0x%x, event is 0x%x \n", $P, $E); + printf("ev4 values are : blahptr 0x%x uint 0x%x int 0x%x\n", + $$.ev4_blahptr, $$.ev4_uint, $$.ev4_int); + } +; diff --git a/sys/netiso/xebec/test_def.h b/sys/netiso/xebec/test_def.h new file mode 100644 index 0000000..6faa2df --- /dev/null +++ b/sys/netiso/xebec/test_def.h @@ -0,0 +1,13 @@ + +struct blah { + unsigned int blahfield; + int dummyi; + char dummyc; +}; + +struct test_pcbstruct { + int test_pcbfield; + int test_state; +}; + +#define MACRO1(arg) if(arg != 0) { printf("macro1\n"); } diff --git a/sys/netiso/xebec/xebec.bnf b/sys/netiso/xebec/xebec.bnf new file mode 100644 index 0000000..d7406d9 --- /dev/null +++ b/sys/netiso/xebec/xebec.bnf @@ -0,0 +1,315 @@ +{ +#include "main.h" +#include "sets.h" +#include <stdio.h> + +extern FILE *eventfile_h, *actfile; +} + +*fmq + + novocab + nobnf + nofirst + nofollow + noparsetable + noerrortables + nos + noe + +*terminals + +ID 0 0 { char *address; } +STRUCT 0 0 +SYNONYM 0 0 +PREDICATE 0 0 { char *address; } +ACTION 0 0 { char *address; } +/* +FSTRING 0 0 { char *address; } +*/ +PROTOCOL 0 0 +LBRACK 0 0 +RBRACK 0 0 +LANGLE 0 0 +EQUAL 0 0 +COMMA 0 0 +STAR 0 0 +EVENTS 0 0 +TRANSITIONS 0 0 +INCLUDE 0 0 +STATES 0 0 +SEMI 0 0 +PCB 0 0 { char *address; } +DEFAULT 0 0 +NULLACTION 0 0 +SAME 0 0 + +*nonterminals + +pcb { char *address; int isevent; } +syn { int type; } +setlist { struct Object *setnum; } +setlisttail { struct Object *setnum; } +part { unsigned char type; } +parttail { unsigned char type; } +partrest { unsigned char type; char *address; } +setstruct { struct Object *object; } +setdef { unsigned char type,keep; char *address; struct Object *object; } +translist +transition +event { struct Object *object; } +oldstate { struct Object *object; } +newstate { struct Object *object; } +predicatepart { char *string; } +actionpart { char *string; struct Object *oldstate; struct Object *newstate; } + +*productions + +program ::= + STAR PROTOCOL ID + { + if(strlen($ID.address) > 50 ) { + fprintf(stderr, + "Protocol name may not exceed 50 chars in length.\n"); + Exit(-1); + } + strcpy(protocol, $ID.address); + openfiles(protocol); + } + STAR includelist + PCB + { + $$pcb.isevent = 0; + } + pcb + { + fprintf(actfile, "\ntypedef %s %s%s;\n", + $pcb[7].address,protocol, PCBNAME); + $$syn.type = PCB_SYN; + } + syn + STAR STATES { $$part.type = (unsigned char) STATESET; } part + STAR { end_states(eventfile_h); } EVENTS + { $$pcb.isevent = 1; } + pcb + { + fprintf(eventfile_h, "\t"); /* fmq gags on single chars */ + includecode(eventfile_h, $pcb[14].address); + fprintf(eventfile_h, "\n"); /* fmq gags on single chars */ + $$syn.type = EVENT_SYN; + } + syn + { + $$part.type = (unsigned char)EVENTSET; + } + part + STAR { end_events(); } + TRANSITIONS + { + putincludes(); + putdriver(actfile, 9); + } + translist +; +pcb ::= STRUCT + { if($pcb.isevent) { + fprintf(stderr, + "Event is a list of objects enclosed by \"{}\"\n"); + Exit(-1); + } + fprintf(eventfile_h, "struct "); + } + ACTION { $pcb.address = $ACTION.address; } + optsemi + ::= ACTION + { if( ! $pcb.isevent) { + fprintf(stderr, + "Pcb requires a type or structure definition.\"{}\"\n"); + Exit(-1); + } + $pcb.address = $ACTION.address; + } + optsemi + ::= ID { $pcb.address = $ID.address; } optsemi +; + +syn ::= SYNONYM ID { synonyms[$syn.type] = stash( $ID.address ); } + ::= +; + +optsemi ::= SEMI + ::= +; +includelist ::= INCLUDE ACTION { includecode(actfile, $ACTION.address);} STAR + ::= +; +part ::= ID + { + $$partrest.address = $ID.address; + $$partrest.type = $part.type; + } + partrest + { $$parttail.type = $part.type; } + parttail +; +parttail ::= { $$part.type = $parttail.type; } part + ::= +; +partrest ::= EQUAL + { + if( lookup( $partrest.type, $partrest.address ) ) { + fprintf(stderr, "bnf:trying to redefine obj type 0x%x, adr %s\n", + $partrest.type, $partrest.address); + Exit(-1); + } + $$setdef.type = $partrest.type; + $$setdef.address = stash( $partrest.address ); + $$setdef.keep = 1; + } setdef { $$setstruct.object = $setdef.object; } setstruct + + ::= ACTION + { + defineitem($partrest.type, + $partrest.address, $ACTION.address); + } + + ::= { + defineitem($partrest.type, $partrest.address, (char *)0); + } +; + +setstruct ::= ACTION + { + if($setstruct.object) { + /* WHEN COULD THIS BE FALSE?? + * isn't it supposed to be setstruct.object??? + * (it used to be $ACTION.address) + */ + + $setstruct.object->obj_struc = $ACTION.address; + fprintf(eventfile_h, + "struct %s %s%s;\n\n", $ACTION.address, + EV_PREFIX, $setstruct.object->obj_name); + } + } + ::= +; + +setdef ::= LBRACK + { + $$setlist.setnum = + defineset($setdef.type, $setdef.address, $setdef.keep); + } setlist RBRACK { $setdef.object = $setlist.setnum; } +; + +setlist ::= ID + { + member($setlist.setnum, $ID.address); + $$setlisttail.setnum = $setlist.setnum; + } setlisttail +; + +setlisttail ::= COMMA { $$setlist.setnum = $setlisttail.setnum; } setlist + ::= +; +translist ::= transition translisttail +; +translisttail ::= translist + ::= +; +transition ::= newstate { transno ++; } LANGLE EQUAL EQUAL oldstate + event + { + CurrentEvent /* GAG! */ = $event.object; + } + predicatepart + { + $$actionpart.string = $predicatepart.string; + $$actionpart.newstate = $newstate.object; + $$actionpart.oldstate = $oldstate.object; + } + actionpart + SEMI +; + +predicatepart ::= PREDICATE + { + $predicatepart.string = stash ( $PREDICATE.address ); + } + ::= DEFAULT + { + $predicatepart.string = (char *)0; + } +; + +actionpart ::= + ACTION + { + statetable( $actionpart.string, $actionpart.oldstate, + $actionpart.newstate, + acttable(actfile, $ACTION.address ), + CurrentEvent ); + if( print_trans ) { + dump_trans( $actionpart.string, $actionpart.oldstate, + $actionpart.newstate, + $ACTION.address, CurrentEvent ); + } + } + ::= NULLACTION + { + statetable($actionpart.string, $actionpart.oldstate, $actionpart.newstate, + 0, CurrentEvent ); /* KLUDGE - remove this */ + if( print_trans ) { + dump_trans( $actionpart.string, $actionpart.oldstate, + $actionpart.newstate, + "NULLACTION", CurrentEvent ); + } + } +; + +oldstate ::= ID + { + $oldstate.object = Lookup(STATESET, $ID.address); + } + ::= { + $$setdef.address = (char *)0; + $$setdef.type = (unsigned char)STATESET; + $$setdef.keep = 0; + } + setdef + { + $oldstate.object = $setdef.object; + } +; + +newstate ::= ID + { + $newstate.object = Lookup(STATESET, $ID.address); + } +; + +newstate ::= SAME + { + extern struct Object *SameState; + + $newstate.object = SameState; + } +; + +event ::= ID + { + $event.object = Lookup(EVENTSET, $ID.address); + } + ::= + { + $$setdef.address = (char *)0; + $$setdef.type = (unsigned char)EVENTSET; + $$setdef.keep = 0; + } + setdef + { + $event.object = $setdef.object; + } +; + +*end diff --git a/sys/netiso/xebec/xebec.c b/sys/netiso/xebec/xebec.c new file mode 100644 index 0000000..132bcb8 --- /dev/null +++ b/sys/netiso/xebec/xebec.c @@ -0,0 +1,451 @@ +/* $Header: xebec.c,v 2.2 88/09/19 12:55:37 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/xebec.c,v $ */ + +#include "xebec.h" +#include "llparse.h" +#ifndef E_TABLE +#define E_TABLE "xebec.e" +#endif E_TABLE + +#include "main.h" +#include "sets.h" +#include <stdio.h> + +extern FILE *eventfile_h, *actfile; + +llaction(lln,token) +LLtoken *token; +{ + struct llattr *llattr; + llattr = &llattrdesc[lldescindex-1]; +switch(lln) { +case 1: + llfinprod(); + break; + +case 10: { + + if(strlen(llattr->llabase[3].ID.address) > 50 ) { + fprintf(stderr, + "Protocol name may not exceed 50 chars in length.\n"); + Exit(-1); + } + strcpy(protocol, llattr->llabase[3].ID.address); + openfiles(protocol); + +} break; + +case 11: { + + llattr->llabase[7].pcb.isevent = 0; + +} break; + +case 12: { + + fprintf(actfile, "\ntypedef %s %s%s;\n", + llattr->llabase[7].pcb.address,protocol, PCBNAME); + llattr->llabase[8].syn.type = PCB_SYN; + +} break; + +case 13: { + llattr->llabase[11].part.type = (unsigned char) STATESET; +} break; + +case 14: { + end_states(eventfile_h); +} break; + +case 15: { + llattr->llabase[14].pcb.isevent = 1; +} break; + +case 16: { + + fprintf(eventfile_h, "\t"); /* fmq gags on single chars */ + includecode(eventfile_h, llattr->llabase[14].pcb.address); + fprintf(eventfile_h, "\n"); /* fmq gags on single chars */ + llattr->llabase[15].syn.type = EVENT_SYN; + +} break; + +case 17: { + + llattr->llabase[16].part.type = (unsigned char)EVENTSET; + +} break; + +case 18: { + end_events(); +} break; + +case 19: { + + putincludes(); + putdriver(actfile, 9); + +} break; + +case 20: { + if(llattr->llabase[0].pcb.isevent) { + fprintf(stderr, + "Event is a list of objects enclosed by \"{}\"\n"); + Exit(-1); + } + fprintf(eventfile_h, "struct "); + +} break; + +case 21: { + llattr->llabase[0].pcb.address = llattr->llabase[2].ACTION.address; +} break; + +case 22: { + if( ! llattr->llabase[0].pcb.isevent) { + fprintf(stderr, + "Pcb requires a type or structure definition.\"{}\"\n"); + Exit(-1); + } + llattr->llabase[0].pcb.address = llattr->llabase[1].ACTION.address; + +} break; + +case 23: { + llattr->llabase[0].pcb.address = llattr->llabase[1].ID.address; +} break; + +case 24: { + synonyms[llattr->llabase[0].syn.type] = stash( llattr->llabase[2].ID.address ); +} break; + +case 25: { + includecode(actfile, llattr->llabase[2].ACTION.address); +} break; + +case 26: { + + llattr->llabase[2].partrest.address = llattr->llabase[1].ID.address; + llattr->llabase[2].partrest.type = llattr->llabase[0].part.type; + +} break; + +case 27: { + llattr->llabase[3].parttail.type = llattr->llabase[0].part.type; +} break; + +case 28: { + llattr->llabase[1].part.type = llattr->llabase[0].parttail.type; +} break; + +case 29: { + + if( lookup( llattr->llabase[0].partrest.type, llattr->llabase[0].partrest.address ) ) { + fprintf(stderr, "bnf:trying to redefine obj type 0x%x, adr %s\n", + llattr->llabase[0].partrest.type, llattr->llabase[0].partrest.address); + Exit(-1); + } + llattr->llabase[2].setdef.type = llattr->llabase[0].partrest.type; + llattr->llabase[2].setdef.address = stash( llattr->llabase[0].partrest.address ); + llattr->llabase[2].setdef.keep = 1; + +} break; + +case 30: { + llattr->llabase[3].setstruct.object = llattr->llabase[2].setdef.object; +} break; + +case 31: { + + defineitem(llattr->llabase[0].partrest.type, + llattr->llabase[0].partrest.address, llattr->llabase[1].ACTION.address); + +} break; + +case 32: { + + defineitem(llattr->llabase[0].partrest.type, llattr->llabase[0].partrest.address, (char *)0); + +} break; + +case 33: { + + if(llattr->llabase[0].setstruct.object) { + /* WHEN COULD THIS BE FALSE?? + * isn't it supposed to be setstruct.object??? + * (it used to be $ACTION.address) + */ + + llattr->llabase[0].setstruct.object->obj_struc = llattr->llabase[1].ACTION.address; + fprintf(eventfile_h, + "struct %s %s%s;\n\n", llattr->llabase[1].ACTION.address, + EV_PREFIX, llattr->llabase[0].setstruct.object->obj_name); + } + +} break; + +case 34: { + + llattr->llabase[2].setlist.setnum = + defineset(llattr->llabase[0].setdef.type, llattr->llabase[0].setdef.address, llattr->llabase[0].setdef.keep); + +} break; + +case 35: { + llattr->llabase[0].setdef.object = llattr->llabase[2].setlist.setnum; +} break; + +case 36: { + + member(llattr->llabase[0].setlist.setnum, llattr->llabase[1].ID.address); + llattr->llabase[2].setlisttail.setnum = llattr->llabase[0].setlist.setnum; + +} break; + +case 37: { + llattr->llabase[2].setlist.setnum = llattr->llabase[0].setlisttail.setnum; +} break; + +case 38: { + transno ++; +} break; + +case 39: { + + CurrentEvent /* GAG! */ = llattr->llabase[6].event.object; + +} break; + +case 40: { + + llattr->llabase[8].actionpart.string = llattr->llabase[7].predicatepart.string; + llattr->llabase[8].actionpart.newstate = llattr->llabase[1].newstate.object; + llattr->llabase[8].actionpart.oldstate = llattr->llabase[5].oldstate.object; + +} break; + +case 41: { + + llattr->llabase[0].predicatepart.string = stash ( llattr->llabase[1].PREDICATE.address ); + +} break; + +case 42: { + + llattr->llabase[0].predicatepart.string = (char *)0; + +} break; + +case 43: { + + statetable( llattr->llabase[0].actionpart.string, llattr->llabase[0].actionpart.oldstate, + llattr->llabase[0].actionpart.newstate, + acttable(actfile, llattr->llabase[1].ACTION.address ), + CurrentEvent ); + if( print_trans ) { + dump_trans( llattr->llabase[0].actionpart.string, llattr->llabase[0].actionpart.oldstate, + llattr->llabase[0].actionpart.newstate, + llattr->llabase[1].ACTION.address, CurrentEvent ); + } + +} break; + +case 44: { + + statetable(llattr->llabase[0].actionpart.string, llattr->llabase[0].actionpart.oldstate, llattr->llabase[0].actionpart.newstate, + 0, CurrentEvent ); /* KLUDGE - remove this */ + if( print_trans ) { + dump_trans( llattr->llabase[0].actionpart.string, llattr->llabase[0].actionpart.oldstate, + llattr->llabase[0].actionpart.newstate, + "NULLACTION", CurrentEvent ); + } + +} break; + +case 45: { + + llattr->llabase[0].oldstate.object = Lookup(STATESET, llattr->llabase[1].ID.address); + +} break; + +case 46: { + + llattr->llabase[1].setdef.address = (char *)0; + llattr->llabase[1].setdef.type = (unsigned char)STATESET; + llattr->llabase[1].setdef.keep = 0; + +} break; + +case 47: { + + llattr->llabase[0].oldstate.object = llattr->llabase[1].setdef.object; + +} break; + +case 48: { + + llattr->llabase[0].newstate.object = Lookup(STATESET, llattr->llabase[1].ID.address); + +} break; + +case 49: { + + extern struct Object *SameState; + + llattr->llabase[0].newstate.object = SameState; + +} break; + +case 50: { + + llattr->llabase[0].event.object = Lookup(EVENTSET, llattr->llabase[1].ID.address); + +} break; + +case 51: { + + llattr->llabase[1].setdef.address = (char *)0; + llattr->llabase[1].setdef.type = (unsigned char)EVENTSET; + llattr->llabase[1].setdef.keep = 0; + +} break; + +case 52: { + + llattr->llabase[0].event.object = llattr->llabase[1].setdef.object; + +} break; +} +} +char *llstrings[] = { + "<null>", + "ID", + "STRUCT", + "SYNONYM", + "PREDICATE", + "ACTION", + "PROTOCOL", + "LBRACK", + "RBRACK", + "LANGLE", + "EQUAL", + "COMMA", + "STAR", + "EVENTS", + "TRANSITIONS", + "INCLUDE", + "STATES", + "SEMI", + "PCB", + "DEFAULT", + "NULLACTION", + "SAME", + "ENDMARKER", + "pcb", + "syn", + "setlist", + "setlisttail", + "part", + "parttail", + "partrest", + "setstruct", + "setdef", + "translist", + "transition", + "event", + "oldstate", + "newstate", + "predicatepart", + "actionpart", + "program", + "includelist", + "optsemi", + "translisttail", + "$goal$", + (char *) 0 +}; +short llnterms = 23; +short llnsyms = 44; +short llnprods = 38; +short llinfinite = 10000; +short llproductions[] = { +41, -21, 5, -20, 2, +41, -22, 5, +41, -23, 1, +-24, 1, 3, + +26, -36, 1, +25, -37, 11, + +28, -27, 29, -26, 1, +27, -28, + +30, -30, 31, -29, 10, +-31, 5, +-32, +-33, 5, + +-35, 8, 25, -34, 7, +42, 33, +17, 38, -40, 37, -39, 34, 35, 10, 10, 9, -38, 36, +-50, 1, +-52, 31, -51, +-45, 1, +-47, 31, -46, +-48, 1, +-49, 21, +-41, 4, +-42, 19, +-43, 5, +-44, 20, +32, -19, 14, -18, 12, 27, -17, 24, -16, 23, -15, 13, -14, 12, 27, -13, 16, 12, 24, -12, 23, -11, 18, 40, 12, -10, 1, 6, 12, +12, -25, 5, 15, + +17, + +32, + +22, 39, +0 +}; +struct llprodindex llprodindex[] = { +{ 0, 0, 0 }, { 0, 5, 19 }, { 5, 3, 3 }, { 8, 3, 2 }, +{ 11, 3, 2 }, { 14, 0, 2 }, { 14, 3, 0 }, { 17, 3, 1 }, +{ 20, 0, 0 }, { 20, 5, 3 }, { 25, 2, 0 }, { 27, 0, 3 }, +{ 27, 5, 1 }, { 32, 2, 0 }, { 34, 1, 3 }, { 35, 2, 1 }, +{ 37, 0, 0 }, { 37, 5, 1 }, { 42, 2, 0 }, { 44, 12, 3 }, +{ 56, 2, 2 }, { 58, 3, 2 }, { 61, 2, 0 }, { 63, 3, 2 }, +{ 66, 2, 1 }, { 68, 2, 0 }, { 70, 2, 9 }, { 72, 2, 1 }, +{ 74, 2, 1 }, { 76, 2, 1 }, { 78, 29, 1 }, { 107, 4, 1 }, +{ 111, 0, 1 }, { 111, 1, 1 }, { 112, 0, 1 }, { 112, 1, 1 }, +{ 113, 0, 1 }, { 113, 2, 2 }, { 0, 0, 0 } +}; +short llepsilon[] = { + 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 1, 0, 1, 0, 0 +}; +struct llparsetable llparsetable[] = { +{ 1, 3 }, { 2, 1 }, { 5, 2 }, { 0, 23 }, { 1, 5 }, +{ 3, 4 }, { 12, 5 }, { 0, 24 }, { 1, 6 }, { 0, 25 }, +{ 8, 8 }, { 11, 7 }, { 0, 26 }, { 1, 9 }, { 0, 27 }, +{ 1, 10 }, { 12, 11 }, { 0, 28 }, { 1, 14 }, { 5, 13 }, +{ 10, 12 }, { 12, 14 }, { 0, 29 }, { 1, 16 }, { 5, 15 }, +{ 12, 16 }, { 0, 30 }, { 7, 17 }, { 0, 31 }, { 1, 18 }, +{ 21, 18 }, { 0, 32 }, { 1, 19 }, { 21, 19 }, { 0, 33 }, +{ 1, 20 }, { 7, 21 }, { 0, 34 }, { 1, 22 }, { 7, 23 }, +{ 0, 35 }, { 1, 24 }, { 21, 25 }, { 0, 36 }, { 4, 26 }, +{ 19, 27 }, { 0, 37 }, { 5, 28 }, { 20, 29 }, { 0, 38 }, +{ 12, 30 }, { 0, 39 }, { 15, 31 }, { 18, 32 }, { 0, 40 }, +{ 1, 34 }, { 3, 34 }, { 12, 34 }, { 17, 33 }, { 0, 41 }, +{ 1, 35 }, { 21, 35 }, { 22, 36 }, { 0, 42 }, { 12, 37 }, +{ 0, 43 }, { 0, 0 } +}; +short llparseindex[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 8, 10, 13, 15, 18, + 23, 27, 29, 32, 35, 38, 41, 44, 47, 50, + 52, 55, 60, 64, 0 +}; diff --git a/sys/netiso/xebec/xebec.h b/sys/netiso/xebec/xebec.h new file mode 100644 index 0000000..168bb77 --- /dev/null +++ b/sys/netiso/xebec/xebec.h @@ -0,0 +1,88 @@ +/* $Header: xebec.h,v 2.1 88/09/19 12:56:35 nhall Exp $ */ +/* $Source: /var/home/tadl/src/argo/xebec/RCS/xebec.h,v $ */ + +union llattrib { + struct { + char *address; } ID; + int STRUCT; + int SYNONYM; + struct { + char *address; } PREDICATE; + struct { + char *address; } ACTION; + int PROTOCOL; + int LBRACK; + int RBRACK; + int LANGLE; + int EQUAL; + int COMMA; + int STAR; + int EVENTS; + int TRANSITIONS; + int INCLUDE; + int STATES; + int SEMI; + struct { + char *address; } PCB; + int DEFAULT; + int NULLACTION; + int SAME; + struct { + char *address; int isevent; } pcb; + struct { + int type; } syn; + struct { + struct Object *setnum; } setlist; + struct { + struct Object *setnum; } setlisttail; + struct { + unsigned char type; } part; + struct { + unsigned char type; } parttail; + struct { + unsigned char type; char *address; } partrest; + struct { + struct Object *object; } setstruct; + struct { + unsigned char type,keep; char *address; struct Object *object; } setdef; + int translist; + int transition; + struct { + struct Object *object; } event; + struct { + struct Object *object; } oldstate; + struct { + struct Object *object; } newstate; + struct { + char *string; } predicatepart; + struct { + char *string; struct Object *oldstate; struct Object *newstate; } actionpart; +}; +#define LLTERM 23 +#define LLSYM 44 +#define LLPROD 38 + +#define LLINF 10000 + +#define T_ID 1 +#define T_STRUCT 2 +#define T_SYNONYM 3 +#define T_PREDICATE 4 +#define T_ACTION 5 +#define T_PROTOCOL 6 +#define T_LBRACK 7 +#define T_RBRACK 8 +#define T_LANGLE 9 +#define T_EQUAL 10 +#define T_COMMA 11 +#define T_STAR 12 +#define T_EVENTS 13 +#define T_TRANSITIONS 14 +#define T_INCLUDE 15 +#define T_STATES 16 +#define T_SEMI 17 +#define T_PCB 18 +#define T_DEFAULT 19 +#define T_NULLACTION 20 +#define T_SAME 21 +#define T_ENDMARKER 22 |