diff options
Diffstat (limited to 'sys/netiso/clnp_options.c')
-rw-r--r-- | sys/netiso/clnp_options.c | 532 |
1 files changed, 532 insertions, 0 deletions
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 */ |