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