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