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.5 (Berkeley) 08/29/89 */ 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 first record rt option */ 129 130 opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp); 131 off = *(opt + 1); 132 rec_start = opt + 2; 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 /* 146 * if there is insufficient room to store the next address, 147 * then terminate recording. Plus 1 on isoa_len is for the 148 * length byte itself 149 */ 150 if (oidx->cni_recrt_len - off < isoa->isoa_len+1) { 151 *(opt + 1) = 0xff; /* terminate recording */ 152 } else { 153 int new_addrlen = isoa->isoa_len + 1; 154 IFDEBUG(D_OPTIONS) 155 printf("clnp_dooptions: clnp_ypocb(x%x, x%x, %d)\n", 156 rec_start, rec_start + new_addrlen, off - 3); 157 ENDDEBUG 158 159 /* move existing records over */ 160 clnp_ypocb(rec_start, rec_start + new_addrlen, off - 3); 161 162 IFDEBUG(D_OPTIONS) 163 printf("clnp_dooptions: new addr at x%x for %d\n", 164 rec_start, new_addrlen); 165 ENDDEBUG 166 167 /* add new record */ 168 *rec_start = isoa->isoa_len; 169 bcopy((caddr_t)isoa, rec_start + 1, isoa->isoa_len); 170 171 /* update offset field */ 172 *(opt + 1) = off + new_addrlen; 173 174 IFDEBUG(D_OPTIONS) 175 printf("clnp_dooptions: new option dump:\n"); 176 dump_buf(opt, oidx->cni_recrt_len); 177 ENDDEBUG 178 } 179 } 180 } 181 } 182 183 /* 184 * FUNCTION: clnp_set_opts 185 * 186 * PURPOSE: Check the data mbuf passed for option sanity. If it is 187 * ok, then set the options ptr to address the data mbuf. 188 * If an options mbuf exists, free it. This implies that 189 * any old options will be lost. If data is NULL, simply 190 * free any old options. 191 * 192 * RETURNS: unix error code 193 * 194 * SIDE EFFECTS: 195 * 196 * NOTES: 197 */ 198 clnp_set_opts(options, data) 199 struct mbuf **options; /* target for option information */ 200 struct mbuf **data; /* source of option information */ 201 { 202 int error = 0; /* error return value */ 203 struct clnp_optidx dummy; /* dummy index - not used */ 204 205 /* 206 * remove any existing options 207 */ 208 if (*options != NULL) { 209 m_freem(*options); 210 *options = NULL; 211 } 212 213 if (*data != NULL) { 214 /* 215 * Insure that the options are reasonable. 216 * 217 * Also, we do not support security, priority, or QOS 218 * nor do we allow one to send an ER option 219 */ 220 if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len, 221 &dummy) != 0) || 222 (dummy.cni_securep) || 223 (dummy.cni_priorp) || 224 (dummy.cni_qos_formatp) || 225 (dummy.cni_er_reason != ER_INVALREAS)) { 226 error = EINVAL; 227 } else { 228 *options = *data; 229 *data = NULL; /* so caller won't free mbuf @ *data */ 230 } 231 } 232 return error; 233 } 234 235 /* 236 * FUNCTION: clnp_opt_sanity 237 * 238 * PURPOSE: Check the options (beginning at opts for len bytes) for 239 * sanity. In addition, fill in the option index structure 240 * in with information about each option discovered. 241 * 242 * RETURNS: success (options check out) - 0 243 * failure - an ER pdu error code describing failure 244 * 245 * SIDE EFFECTS: 246 * 247 * NOTES: Each pointer field of the option index is filled in with 248 * the offset from the beginning of the mbuf data, not the 249 * actual address. 250 */ 251 clnp_opt_sanity(m, opts, len, oidx) 252 struct mbuf *m; /* mbuf options reside in */ 253 caddr_t opts; /* ptr to buffer containing options */ 254 int len; /* length of buffer */ 255 struct clnp_optidx *oidx; /* RETURN: filled in with option idx info */ 256 { 257 u_char opcode; /* code of particular option */ 258 u_char oplen; /* length of a particular option */ 259 caddr_t opts_end; /* ptr to end of options */ 260 u_char pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0; 261 /* flags for catching duplicate options */ 262 263 IFDEBUG(D_OPTIONS) 264 printf("clnp_opt_sanity: checking %d bytes of data:\n", len); 265 dump_buf(opts, len); 266 ENDDEBUG 267 268 /* clear option index field if passed */ 269 bzero((caddr_t)oidx, sizeof(struct clnp_optidx)); 270 271 /* 272 * We need to indicate whether the ER option is present. This is done 273 * by overloading the er_reason field to also indicate presense of 274 * the option along with the option value. I would like ER_INVALREAS 275 * to have value 0, but alas, 0 is a valid er reason... 276 */ 277 oidx->cni_er_reason = ER_INVALREAS; 278 279 opts_end = opts + len; 280 while (opts < opts_end) { 281 /* must have at least 2 bytes per option (opcode and len) */ 282 if (opts + 2 > opts_end) 283 return(GEN_INCOMPLETE); 284 285 opcode = *opts++; 286 oplen = *opts++; 287 IFDEBUG(D_OPTIONS) 288 printf("clnp_opt_sanity: opcode is %x and oplen %d\n", 289 opcode, oplen); 290 printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT); 291 292 switch (opcode) { 293 case CLNPOVAL_PAD: { 294 printf("CLNPOVAL_PAD\n"); 295 } break; 296 case CLNPOVAL_SECURE: { 297 printf("CLNPOVAL_SECURE\n"); 298 } break; 299 case CLNPOVAL_SRCRT: { 300 printf("CLNPOVAL_SRCRT\n"); 301 } break; 302 case CLNPOVAL_RECRT: { 303 printf("CLNPOVAL_RECRT\n"); 304 } break; 305 case CLNPOVAL_QOS: { 306 printf("CLNPOVAL_QOS\n"); 307 } break; 308 case CLNPOVAL_PRIOR: { 309 printf("CLNPOVAL_PRIOR\n"); 310 } break; 311 case CLNPOVAL_ERREAS: { 312 printf("CLNPOVAL_ERREAS\n"); 313 } break; 314 default: 315 printf("UKNOWN option %x\n", opcode); 316 } 317 ENDDEBUG 318 319 /* don't allow crazy length values */ 320 if (opts + oplen > opts_end) 321 return(GEN_INCOMPLETE); 322 323 switch (opcode) { 324 case CLNPOVAL_PAD: { 325 /* 326 * Padding: increment pointer by length of padding 327 */ 328 if (pad++) /* duplicate ? */ 329 return(GEN_DUPOPT); 330 opts += oplen; 331 } break; 332 333 case CLNPOVAL_SECURE: { 334 u_char format = *opts; 335 336 if (secure++) /* duplicate ? */ 337 return(GEN_DUPOPT); 338 /* 339 * Security: high 2 bits of first octet indicate format 340 * (00 in high bits is reserved). 341 * Remaining bits must be 0. Remaining octets indicate 342 * actual security 343 */ 344 if (((format & 0x3f) > 0) || /* low 6 bits set ? */ 345 ((format & 0xc0) == 0)) /* high 2 bits zero ? */ 346 return(GEN_HDRSYNTAX); 347 348 oidx->cni_securep = CLNP_OPTTOOFF(m, opts); 349 oidx->cni_secure_len = oplen; 350 opts += oplen; 351 } break; 352 353 case CLNPOVAL_SRCRT: { 354 u_char type, offset; /* type of rt, offset of start */ 355 caddr_t route_end; /* address of end of route option */ 356 357 IFDEBUG(D_OPTIONS) 358 printf("clnp_opt_sanity: SRC RT\n"); 359 ENDDEBUG 360 361 if (srcrt++) /* duplicate ? */ 362 return(GEN_DUPOPT); 363 /* 364 * source route: There must be 2 bytes following the length 365 * field: type and offset. The type must be either 366 * partial route or complete route. The offset field must 367 * be within the option. A single exception is made, however. 368 * The offset may be 1 greater than the length. This case 369 * occurs when the last source route record is consumed. 370 * In this case, we ignore the source route option. 371 * RAH? You should be able to set offset to 'ff' like in record 372 * route! 373 * Following this is a series of address fields. 374 * Each address field is composed of a (length, address) pair. 375 * Insure that the offset and each address length is reasonable 376 */ 377 route_end = opts + oplen; 378 379 if (opts + 2 > route_end) 380 return(SRCRT_SYNTAX); 381 382 type = *opts; 383 offset = *(opts+1); 384 385 386 /* type must be partial or complete */ 387 if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) 388 return(SRCRT_SYNTAX); 389 390 oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts); 391 oidx->cni_srcrt_len = oplen; 392 393 opts += offset-1; /*set opts to first addr in rt */ 394 395 /* 396 * Offset must be reasonable: 397 * less than end of options, or equal to end of options 398 */ 399 if (opts >= route_end) { 400 if (opts == route_end) { 401 IFDEBUG(D_OPTIONS) 402 printf("clnp_opt_sanity: end of src route info\n"); 403 ENDDEBUG 404 break; 405 } else 406 return(SRCRT_SYNTAX); 407 } 408 409 while (opts < route_end) { 410 u_char addrlen = *opts++; 411 if (opts + addrlen > route_end) 412 return(SRCRT_SYNTAX); 413 opts += addrlen; 414 } 415 } break; 416 case CLNPOVAL_RECRT: { 417 u_char type, offset; /* type of rt, offset of start */ 418 caddr_t record_end; /* address of end of record option */ 419 420 if (recrt++) /* duplicate ? */ 421 return(GEN_DUPOPT); 422 /* 423 * record route: after the length field, expect a 424 * type and offset. Type must be partial or complete. 425 * Offset indicates where to start recording. Insure it 426 * is within the option. All ones for offset means 427 * recording is terminated. 428 */ 429 record_end = opts + oplen; 430 431 oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts); 432 oidx->cni_recrt_len = oplen; 433 434 if (opts + 2 > record_end) 435 return(GEN_INCOMPLETE); 436 437 type = *opts; 438 offset = *(opts+1); 439 440 /* type must be partial or complete */ 441 if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT))) 442 return(GEN_HDRSYNTAX); 443 444 /* offset must be reasonable */ 445 if ((offset < 0xff) && (opts + offset > record_end)) 446 return(GEN_HDRSYNTAX); 447 opts += oplen; 448 } break; 449 case CLNPOVAL_QOS: { 450 u_char format = *opts; 451 452 if (qos++) /* duplicate ? */ 453 return(GEN_DUPOPT); 454 /* 455 * qos: high 2 bits of first octet indicate format 456 * (00 in high bits is reserved). 457 * Remaining bits must be 0 (unless format indicates 458 * globally unique qos, in which case remaining bits indicate 459 * qos (except bit 6 which is reserved)). Otherwise, 460 * remaining octets indicate actual qos. 461 */ 462 if (((format & 0xc0) == 0) || /* high 2 bits zero ? */ 463 (((format & 0xc0) != CLNPOVAL_GLOBAL) && 464 ((format & 0x3f) > 0))) /* not global,low bits used ? */ 465 return(GEN_HDRSYNTAX); 466 467 oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts); 468 oidx->cni_qos_len = oplen; 469 470 opts += oplen; 471 } break; 472 473 case CLNPOVAL_PRIOR: { 474 if (prior++) /* duplicate ? */ 475 return(GEN_DUPOPT); 476 /* 477 * priority: value must be one byte long 478 */ 479 if (oplen != 1) 480 return(GEN_HDRSYNTAX); 481 482 oidx->cni_priorp = CLNP_OPTTOOFF(m, opts); 483 484 opts += oplen; 485 } break; 486 487 case CLNPOVAL_ERREAS: { 488 /* 489 * er reason: value must be two bytes long 490 */ 491 if (oplen != 2) 492 return(GEN_HDRSYNTAX); 493 494 oidx->cni_er_reason = *opts; 495 496 opts += oplen; 497 } break; 498 499 default: { 500 IFDEBUG(D_OPTIONS) 501 printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode); 502 ENDDEBUG 503 return(DISC_UNSUPPOPT); 504 } 505 } 506 } 507 IFDEBUG(D_OPTIONS) 508 printf("clnp_opt_sanity: return(0)\n", opcode); 509 ENDDEBUG 510 return(0); 511 } 512 #endif ISO 513