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