1*36371Ssklower /*********************************************************** 2*36371Ssklower Copyright IBM Corporation 1987 3*36371Ssklower 4*36371Ssklower All Rights Reserved 5*36371Ssklower 6*36371Ssklower Permission to use, copy, modify, and distribute this software and its 7*36371Ssklower documentation for any purpose and without fee is hereby granted, 8*36371Ssklower provided that the above copyright notice appear in all copies and that 9*36371Ssklower both that copyright notice and this permission notice appear in 10*36371Ssklower supporting documentation, and that the name of IBM not be 11*36371Ssklower used in advertising or publicity pertaining to distribution of the 12*36371Ssklower software without specific, written prior permission. 13*36371Ssklower 14*36371Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*36371Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16*36371Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17*36371Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18*36371Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19*36371Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*36371Ssklower SOFTWARE. 21*36371Ssklower 22*36371Ssklower ******************************************************************/ 23*36371Ssklower 24*36371Ssklower /* 25*36371Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26*36371Ssklower */ 27*36371Ssklower /* $Header: clnp_options.c,v 4.3 88/09/15 18:57:36 hagens Exp $ */ 28*36371Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_options.c,v $ */ 29*36371Ssklower 30*36371Ssklower #ifndef lint 31*36371Ssklower static char *rcsid = "$Header: clnp_options.c,v 4.3 88/09/15 18:57:36 hagens Exp $"; 32*36371Ssklower #endif lint 33*36371Ssklower 34*36371Ssklower #ifdef ISO 35*36371Ssklower 36*36371Ssklower #include "../h/types.h" 37*36371Ssklower #include "../h/param.h" 38*36371Ssklower #include "../h/mbuf.h" 39*36371Ssklower #include "../h/domain.h" 40*36371Ssklower #include "../h/protosw.h" 41*36371Ssklower #include "../h/socket.h" 42*36371Ssklower #include "../h/socketvar.h" 43*36371Ssklower #include "../h/errno.h" 44*36371Ssklower 45*36371Ssklower #include "../net/if.h" 46*36371Ssklower #include "../net/route.h" 47*36371Ssklower 48*36371Ssklower #include "../netiso/iso.h" 49*36371Ssklower #include "../netiso/clnp.h" 50*36371Ssklower #include "../netiso/clnp_stat.h" 51*36371Ssklower #include "../netiso/argo_debug.h" 52*36371Ssklower 53*36371Ssklower /* 54*36371Ssklower * FUNCTION: clnp_update_srcrt 55*36371Ssklower * 56*36371Ssklower * PURPOSE: Process src rt option accompanying a clnp datagram. 57*36371Ssklower * - bump src route ptr if src routing and 58*36371Ssklower * we appear current in src route list. 59*36371Ssklower * 60*36371Ssklower * RETURNS: none 61*36371Ssklower * 62*36371Ssklower * SIDE EFFECTS: 63*36371Ssklower * 64*36371Ssklower * NOTES: If source routing has been terminated, do nothing. 65*36371Ssklower */ 66*36371Ssklower clnp_update_srcrt(options, oidx) 67*36371Ssklower struct mbuf *options; /* ptr to options mbuf */ 68*36371Ssklower struct clnp_optidx *oidx; /* ptr to option index */ 69*36371Ssklower { 70*36371Ssklower u_char len; /* length of current address */ 71*36371Ssklower struct iso_addr isoa; /* copy current address into here */ 72*36371Ssklower 73*36371Ssklower if (CLNPSRCRT_TERM(oidx, options)) { 74*36371Ssklower IFDEBUG(D_OPTIONS) 75*36371Ssklower printf("clnp_update_srcrt: src rt terminated\n"); 76*36371Ssklower ENDDEBUG 77*36371Ssklower return; 78*36371Ssklower } 79*36371Ssklower 80*36371Ssklower len = CLNPSRCRT_CLEN(oidx, options); 81*36371Ssklower bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&isoa, len); 82*36371Ssklower isoa.isoa_len = len; 83*36371Ssklower 84*36371Ssklower IFDEBUG(D_OPTIONS) 85*36371Ssklower printf("clnp_update_srcrt: current src rt: %s\n", 86*36371Ssklower clnp_iso_addrp(&isoa)); 87*36371Ssklower ENDDEBUG 88*36371Ssklower 89*36371Ssklower if (clnp_ours(&isoa)) { 90*36371Ssklower IFDEBUG(D_OPTIONS) 91*36371Ssklower printf("clnp_update_srcrt: updating src rt\n"); 92*36371Ssklower ENDDEBUG 93*36371Ssklower 94*36371Ssklower /* update pointer to next src route */ 95*36371Ssklower len++; /* count length byte too! */ 96*36371Ssklower CLNPSRCRT_OFF(oidx, options) += len; 97*36371Ssklower } 98*36371Ssklower } 99*36371Ssklower 100*36371Ssklower /* 101*36371Ssklower * FUNCTION: clnp_dooptions 102*36371Ssklower * 103*36371Ssklower * PURPOSE: Process options accompanying a clnp datagram. 104*36371Ssklower * Processing includes 105*36371Ssklower * - log our address if recording route 106*36371Ssklower * 107*36371Ssklower * RETURNS: none 108*36371Ssklower * 109*36371Ssklower * SIDE EFFECTS: 110*36371Ssklower * 111*36371Ssklower * NOTES: 112*36371Ssklower */ 113*36371Ssklower clnp_dooptions(options, oidx, ifp, isoa) 114*36371Ssklower struct mbuf *options; /* ptr to options mbuf */ 115*36371Ssklower struct clnp_optidx *oidx; /* ptr to option index */ 116*36371Ssklower struct ifnet *ifp; /* ptr to interface pkt is leaving on */ 117*36371Ssklower struct iso_addr *isoa; /* ptr to our address for this ifp */ 118*36371Ssklower { 119*36371Ssklower /* 120*36371Ssklower * If record route is specified, move all 121*36371Ssklower * existing records over, and insert the address of 122*36371Ssklower * interface passed 123*36371Ssklower */ 124*36371Ssklower if (oidx->cni_recrtp) { 125*36371Ssklower char *opt; /* ptr to beginning of recrt option */ 126*36371Ssklower u_char off; /* offset from opt of first free byte */ 127*36371Ssklower char *rec_start; /* beginning of first record rt option */ 128*36371Ssklower 129*36371Ssklower opt = oidx->cni_recrtp + (caddr_t)options; 130*36371Ssklower off = *(opt + 1); 131*36371Ssklower rec_start = opt + 2; 132*36371Ssklower 133*36371Ssklower IFDEBUG(D_OPTIONS) 134*36371Ssklower printf("clnp_dooptions: record route: option x%x for %d bytes\n", 135*36371Ssklower opt, oidx->cni_recrt_len); 136*36371Ssklower printf("\tfree slot offset x%x\n", off); 137*36371Ssklower printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa)); 138*36371Ssklower printf("clnp_dooptions: option dump:\n"); 139*36371Ssklower dump_buf(opt, oidx->cni_recrt_len); 140*36371Ssklower ENDDEBUG 141*36371Ssklower 142*36371Ssklower /* proceed only if recording has not been terminated */ 143*36371Ssklower if (off != 0xff) { 144*36371Ssklower /* 145*36371Ssklower * if there is insufficient room to store the next address, 146*36371Ssklower * then terminate recording. Plus 1 on isoa_len is for the 147*36371Ssklower * length byte itself 148*36371Ssklower */ 149*36371Ssklower if (oidx->cni_recrt_len - off < isoa->isoa_len+1) { 150*36371Ssklower *(opt + 1) = 0xff; /* terminate recording */ 151*36371Ssklower } else { 152*36371Ssklower int new_addrlen = isoa->isoa_len + 1; 153*36371Ssklower IFDEBUG(D_OPTIONS) 154*36371Ssklower printf("clnp_dooptions: clnp_ypocb(x%x, x%x, %d)\n", 155*36371Ssklower rec_start, rec_start + new_addrlen, off - 3); 156*36371Ssklower ENDDEBUG 157*36371Ssklower 158*36371Ssklower /* move existing records over */ 159*36371Ssklower clnp_ypocb(rec_start, rec_start + new_addrlen, off - 3); 160*36371Ssklower 161*36371Ssklower IFDEBUG(D_OPTIONS) 162*36371Ssklower printf("clnp_dooptions: new addr at x%x for %d\n", 163*36371Ssklower rec_start, new_addrlen); 164*36371Ssklower ENDDEBUG 165*36371Ssklower 166*36371Ssklower /* add new record */ 167*36371Ssklower *rec_start = isoa->isoa_len; 168*36371Ssklower bcopy((caddr_t)isoa, rec_start + 1, isoa->isoa_len); 169*36371Ssklower 170*36371Ssklower /* update offset field */ 171*36371Ssklower *(opt + 1) = off + new_addrlen; 172*36371Ssklower 173*36371Ssklower IFDEBUG(D_OPTIONS) 174*36371Ssklower printf("clnp_dooptions: new option dump:\n"); 175*36371Ssklower dump_buf(opt, oidx->cni_recrt_len); 176*36371Ssklower ENDDEBUG 177*36371Ssklower } 178*36371Ssklower } 179*36371Ssklower } 180*36371Ssklower } 181*36371Ssklower 182*36371Ssklower /* 183*36371Ssklower * FUNCTION: clnp_set_opts 184*36371Ssklower * 185*36371Ssklower * PURPOSE: Check the data mbuf passed for option sanity. If it is 186*36371Ssklower * ok, then set the options ptr to address the data mbuf. 187*36371Ssklower * If an options mbuf exists, free it. This implies that 188*36371Ssklower * any old options will be lost. If data is NULL, simply 189*36371Ssklower * free any old options. 190*36371Ssklower * 191*36371Ssklower * RETURNS: unix error code 192*36371Ssklower * 193*36371Ssklower * SIDE EFFECTS: 194*36371Ssklower * 195*36371Ssklower * NOTES: 196*36371Ssklower */ 197*36371Ssklower clnp_set_opts(options, data) 198*36371Ssklower struct mbuf **options; /* target for option information */ 199*36371Ssklower struct mbuf **data; /* source of option information */ 200*36371Ssklower { 201*36371Ssklower int error = 0; /* error return value */ 202*36371Ssklower struct clnp_optidx dummy; /* dummy index - not used */ 203*36371Ssklower 204*36371Ssklower /* 205*36371Ssklower * remove any existing options 206*36371Ssklower */ 207*36371Ssklower if (*options != NULL) { 208*36371Ssklower m_freem(*options); 209*36371Ssklower *options = NULL; 210*36371Ssklower } 211*36371Ssklower 212*36371Ssklower if (*data != NULL) { 213*36371Ssklower /* 214*36371Ssklower * Insure that the options are reasonable. 215*36371Ssklower * 216*36371Ssklower * Also, we do not support security, priority, or QOS 217*36371Ssklower * nor do we allow one to send an ER option 218*36371Ssklower */ 219*36371Ssklower if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len, 220*36371Ssklower &dummy) != 0) || 221*36371Ssklower (dummy.cni_securep) || 222*36371Ssklower (dummy.cni_priorp) || 223*36371Ssklower (dummy.cni_qos_formatp) || 224*36371Ssklower (dummy.cni_er_reason != ER_INVALREAS)) { 225*36371Ssklower error = EINVAL; 226*36371Ssklower } else { 227*36371Ssklower *options = *data; 228*36371Ssklower *data = NULL; /* so caller won't free mbuf @ *data */ 229*36371Ssklower } 230*36371Ssklower } 231*36371Ssklower return error; 232*36371Ssklower } 233*36371Ssklower 234*36371Ssklower /* 235*36371Ssklower * FUNCTION: clnp_opt_sanity 236*36371Ssklower * 237*36371Ssklower * PURPOSE: Check the options (beginning at opts for len bytes) for 238*36371Ssklower * sanity. In addition, fill in the option index structure 239*36371Ssklower * in with information about each option discovered. 240*36371Ssklower * 241*36371Ssklower * RETURNS: success (options check out) - 0 242*36371Ssklower * failure - an ER pdu error code describing failure 243*36371Ssklower * 244*36371Ssklower * SIDE EFFECTS: 245*36371Ssklower * 246*36371Ssklower * NOTES: Each pointer field of the option index is filled in with 247*36371Ssklower * the offset from the beginning of the mbuf, not the 248*36371Ssklower * actual address. 249*36371Ssklower */ 250*36371Ssklower clnp_opt_sanity(m, opts, len, oidx) 251*36371Ssklower struct mbuf *m; /* mbuf options reside in */ 252*36371Ssklower caddr_t opts; /* ptr to buffer containing options */ 253*36371Ssklower int len; /* length of buffer */ 254*36371Ssklower struct clnp_optidx *oidx; /* RETURN: filled in with option idx info */ 255*36371Ssklower { 256*36371Ssklower u_char opcode; /* code of particular option */ 257*36371Ssklower u_char oplen; /* length of a particular option */ 258*36371Ssklower caddr_t opts_end; /* ptr to end of options */ 259*36371Ssklower u_char pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0; 260*36371Ssklower /* flags for catching duplicate options */ 261*36371Ssklower 262*36371Ssklower IFDEBUG(D_OPTIONS) 263*36371Ssklower printf("clnp_opt_sanity: checking %d bytes of data:\n", len); 264*36371Ssklower dump_buf(opts, len); 265*36371Ssklower ENDDEBUG 266*36371Ssklower 267*36371Ssklower /* clear option index field if passed */ 268*36371Ssklower bzero((caddr_t)oidx, sizeof(struct clnp_optidx)); 269*36371Ssklower 270*36371Ssklower /* 271*36371Ssklower * We need to indicate whether the ER option is present. This is done 272*36371Ssklower * by overloading the er_reason field to also indicate presense of 273*36371Ssklower * the option along with the option value. I would like ER_INVALREAS 274*36371Ssklower * to have value 0, but alas, 0 is a valid er reason... 275*36371Ssklower */ 276*36371Ssklower oidx->cni_er_reason = ER_INVALREAS; 277*36371Ssklower 278*36371Ssklower opts_end = opts + len; 279*36371Ssklower while (opts < opts_end) { 280*36371Ssklower /* must have at least 2 bytes per option (opcode and len) */ 281*36371Ssklower if (opts + 2 > opts_end) 282*36371Ssklower return(GEN_INCOMPLETE); 283*36371Ssklower 284*36371Ssklower opcode = *opts++; 285*36371Ssklower oplen = *opts++; 286*36371Ssklower IFDEBUG(D_OPTIONS) 287*36371Ssklower printf("clnp_opt_sanity: opcode is %x and oplen %d\n", 288*36371Ssklower opcode, oplen); 289*36371Ssklower printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT); 290*36371Ssklower 291*36371Ssklower switch (opcode) { 292*36371Ssklower case CLNPOVAL_PAD: { 293*36371Ssklower printf("CLNPOVAL_PAD\n"); 294*36371Ssklower } break; 295*36371Ssklower case CLNPOVAL_SECURE: { 296*36371Ssklower printf("CLNPOVAL_SECURE\n"); 297*36371Ssklower } break; 298*36371Ssklower case CLNPOVAL_SRCRT: { 299*36371Ssklower printf("CLNPOVAL_SRCRT\n"); 300*36371Ssklower } break; 301*36371Ssklower case CLNPOVAL_RECRT: { 302*36371Ssklower printf("CLNPOVAL_RECRT\n"); 303*36371Ssklower } break; 304*36371Ssklower case CLNPOVAL_QOS: { 305*36371Ssklower printf("CLNPOVAL_QOS\n"); 306*36371Ssklower } break; 307*36371Ssklower case CLNPOVAL_PRIOR: { 308*36371Ssklower printf("CLNPOVAL_PRIOR\n"); 309*36371Ssklower } break; 310*36371Ssklower case CLNPOVAL_ERREAS: { 311*36371Ssklower printf("CLNPOVAL_ERREAS\n"); 312*36371Ssklower } break; 313*36371Ssklower default: 314*36371Ssklower printf("UKNOWN option %x\n", opcode); 315*36371Ssklower } 316*36371Ssklower ENDDEBUG 317*36371Ssklower 318*36371Ssklower /* don't allow crazy length values */ 319*36371Ssklower if (opts + oplen > opts_end) 320*36371Ssklower return(GEN_INCOMPLETE); 321*36371Ssklower 322*36371Ssklower switch (opcode) { 323*36371Ssklower case CLNPOVAL_PAD: { 324*36371Ssklower /* 325*36371Ssklower * Padding: increment pointer by length of padding 326*36371Ssklower */ 327*36371Ssklower if (pad++) /* duplicate ? */ 328*36371Ssklower return(GEN_DUPOPT); 329*36371Ssklower opts += oplen; 330*36371Ssklower } break; 331*36371Ssklower 332*36371Ssklower case CLNPOVAL_SECURE: { 333*36371Ssklower u_char format = *opts; 334*36371Ssklower 335*36371Ssklower if (secure++) /* duplicate ? */ 336*36371Ssklower return(GEN_DUPOPT); 337*36371Ssklower /* 338*36371Ssklower * Security: high 2 bits of first octet indicate format 339*36371Ssklower * (00 in high bits is reserved). 340*36371Ssklower * Remaining bits must be 0. Remaining octets indicate 341*36371Ssklower * actual security 342*36371Ssklower */ 343*36371Ssklower if (((format & 0x3f) > 0) || /* low 6 bits set ? */ 344*36371Ssklower ((format & 0xc0) == 0)) /* high 2 bits zero ? */ 345*36371Ssklower return(GEN_HDRSYNTAX); 346*36371Ssklower 347*36371Ssklower oidx->cni_securep = opts - (caddr_t)m; 348*36371Ssklower oidx->cni_secure_len = oplen; 349*36371Ssklower opts += oplen; 350*36371Ssklower } break; 351*36371Ssklower 352*36371Ssklower case CLNPOVAL_SRCRT: { 353*36371Ssklower u_char type, offset; /* type of rt, offset of start */ 354*36371Ssklower caddr_t route_end; /* address of end of route option */ 355*36371Ssklower 356*36371Ssklower IFDEBUG(D_OPTIONS) 357*36371Ssklower printf("clnp_opt_sanity: SRC RT\n"); 358*36371Ssklower ENDDEBUG 359*36371Ssklower 360*36371Ssklower if (srcrt++) /* duplicate ? */ 361*36371Ssklower return(GEN_DUPOPT); 362*36371Ssklower /* 363*36371Ssklower * source route: There must be 2 bytes following the length 364*36371Ssklower * field: type and offset. The type must be either 365*36371Ssklower * partial route or complete route. The offset field must 366*36371Ssklower * be within the option. A single exception is made, however. 367*36371Ssklower * The offset may be 1 greater than the length. This case 368*36371Ssklower * occurs when the last source route record is consumed. 369*36371Ssklower * In this case, we ignore the source route option. 370*36371Ssklower * RAH? You should be able to set offset to 'ff' like in record 371*36371Ssklower * route! 372*36371Ssklower * Following this is a series of address fields. 373*36371Ssklower * Each address field is composed of a (length, address) pair. 374*36371Ssklower * Insure that the offset and each address length is reasonable 375*36371Ssklower */ 376*36371Ssklower route_end = opts + oplen; 377*36371Ssklower 378*36371Ssklower if (opts + 2 > route_end) 379*36371Ssklower return(SRCRT_SYNTAX); 380*36371Ssklower 381*36371Ssklower type = *opts; 382*36371Ssklower offset = *(opts+1); 383*36371Ssklower 384*36371Ssklower 385*36371Ssklower /* type must be partial or complete */ 386*36371Ssklower if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) 387*36371Ssklower return(SRCRT_SYNTAX); 388*36371Ssklower 389*36371Ssklower oidx->cni_srcrt_s = opts - (caddr_t)m; 390*36371Ssklower oidx->cni_srcrt_len = oplen; 391*36371Ssklower 392*36371Ssklower opts += offset-1; /*set opts to first addr in rt */ 393*36371Ssklower 394*36371Ssklower /* 395*36371Ssklower * Offset must be reasonable: 396*36371Ssklower * less than end of options, or equal to end of options 397*36371Ssklower */ 398*36371Ssklower if (opts >= route_end) { 399*36371Ssklower if (opts == route_end) { 400*36371Ssklower IFDEBUG(D_OPTIONS) 401*36371Ssklower printf("clnp_opt_sanity: end of src route info\n"); 402*36371Ssklower ENDDEBUG 403*36371Ssklower break; 404*36371Ssklower } else 405*36371Ssklower return(SRCRT_SYNTAX); 406*36371Ssklower } 407*36371Ssklower 408*36371Ssklower while (opts < route_end) { 409*36371Ssklower u_char addrlen = *opts++; 410*36371Ssklower if (opts + addrlen > route_end) 411*36371Ssklower return(SRCRT_SYNTAX); 412*36371Ssklower opts += addrlen; 413*36371Ssklower } 414*36371Ssklower } break; 415*36371Ssklower case CLNPOVAL_RECRT: { 416*36371Ssklower u_char type, offset; /* type of rt, offset of start */ 417*36371Ssklower caddr_t record_end; /* address of end of record option */ 418*36371Ssklower 419*36371Ssklower if (recrt++) /* duplicate ? */ 420*36371Ssklower return(GEN_DUPOPT); 421*36371Ssklower /* 422*36371Ssklower * record route: after the length field, expect a 423*36371Ssklower * type and offset. Type must be partial or complete. 424*36371Ssklower * Offset indicates where to start recording. Insure it 425*36371Ssklower * is within the option. All ones for offset means 426*36371Ssklower * recording is terminated. 427*36371Ssklower */ 428*36371Ssklower record_end = opts + oplen; 429*36371Ssklower 430*36371Ssklower oidx->cni_recrtp = opts - (caddr_t)m; 431*36371Ssklower oidx->cni_recrt_len = oplen; 432*36371Ssklower 433*36371Ssklower if (opts + 2 > record_end) 434*36371Ssklower return(GEN_INCOMPLETE); 435*36371Ssklower 436*36371Ssklower type = *opts; 437*36371Ssklower offset = *(opts+1); 438*36371Ssklower 439*36371Ssklower /* type must be partial or complete */ 440*36371Ssklower if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) 441*36371Ssklower return(GEN_HDRSYNTAX); 442*36371Ssklower 443*36371Ssklower /* offset must be reasonable */ 444*36371Ssklower if ((offset < 0xff) && (opts + offset > record_end)) 445*36371Ssklower return(GEN_HDRSYNTAX); 446*36371Ssklower opts += oplen; 447*36371Ssklower } break; 448*36371Ssklower case CLNPOVAL_QOS: { 449*36371Ssklower u_char format = *opts; 450*36371Ssklower 451*36371Ssklower if (qos++) /* duplicate ? */ 452*36371Ssklower return(GEN_DUPOPT); 453*36371Ssklower /* 454*36371Ssklower * qos: high 2 bits of first octet indicate format 455*36371Ssklower * (00 in high bits is reserved). 456*36371Ssklower * Remaining bits must be 0 (unless format indicates 457*36371Ssklower * globally unique qos, in which case remaining bits indicate 458*36371Ssklower * qos (except bit 6 which is reserved)). Otherwise, 459*36371Ssklower * remaining octets indicate actual qos. 460*36371Ssklower */ 461*36371Ssklower if (((format & 0xc0) == 0) || /* high 2 bits zero ? */ 462*36371Ssklower (((format & 0xc0) != CLNPOVAL_GLOBAL) && 463*36371Ssklower ((format & 0x3f) > 0))) /* not global,low bits used ? */ 464*36371Ssklower return(GEN_HDRSYNTAX); 465*36371Ssklower 466*36371Ssklower oidx->cni_qos_formatp = opts - (caddr_t)m; 467*36371Ssklower oidx->cni_qos_len = oplen; 468*36371Ssklower 469*36371Ssklower opts += oplen; 470*36371Ssklower } break; 471*36371Ssklower 472*36371Ssklower case CLNPOVAL_PRIOR: { 473*36371Ssklower if (prior++) /* duplicate ? */ 474*36371Ssklower return(GEN_DUPOPT); 475*36371Ssklower /* 476*36371Ssklower * priority: value must be one byte long 477*36371Ssklower */ 478*36371Ssklower if (oplen != 1) 479*36371Ssklower return(GEN_HDRSYNTAX); 480*36371Ssklower 481*36371Ssklower oidx->cni_priorp = opts - (caddr_t)m; 482*36371Ssklower 483*36371Ssklower opts += oplen; 484*36371Ssklower } break; 485*36371Ssklower 486*36371Ssklower case CLNPOVAL_ERREAS: { 487*36371Ssklower /* 488*36371Ssklower * er reason: value must be two bytes long 489*36371Ssklower */ 490*36371Ssklower if (oplen != 2) 491*36371Ssklower return(GEN_HDRSYNTAX); 492*36371Ssklower 493*36371Ssklower oidx->cni_er_reason = *opts; 494*36371Ssklower 495*36371Ssklower opts += oplen; 496*36371Ssklower } break; 497*36371Ssklower 498*36371Ssklower default: { 499*36371Ssklower IFDEBUG(D_OPTIONS) 500*36371Ssklower printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode); 501*36371Ssklower ENDDEBUG 502*36371Ssklower return(DISC_UNSUPPOPT); 503*36371Ssklower } 504*36371Ssklower } 505*36371Ssklower } 506*36371Ssklower IFDEBUG(D_OPTIONS) 507*36371Ssklower printf("clnp_opt_sanity: return(0)\n", opcode); 508*36371Ssklower ENDDEBUG 509*36371Ssklower return(0); 510*36371Ssklower } 511*36371Ssklower #endif ISO 512