make tags for header file too
[unix-history] / usr / src / sys / netiso / clnp_options.c
CommitLineData
ad140953
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
e5c263cf
KS
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 $ */
ad140953
KS
29
30#ifndef lint
e5c263cf 31static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_options.c,v 5.1 89/02/09 16:20:37 hagens Exp $";
ad140953
KS
32#endif lint
33
34#ifdef ISO
35
e663c139
KM
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"
ad140953
KS
44
45#include "../net/if.h"
46#include "../net/route.h"
47
a50e2bc0
KS
48#include "iso.h"
49#include "clnp.h"
50#include "clnp_stat.h"
51#include "argo_debug.h"
ad140953
KS
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 */
66clnp_update_srcrt(options, oidx)
67struct mbuf *options; /* ptr to options mbuf */
68struct 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 */
113clnp_dooptions(options, oidx, ifp, isoa)
114struct mbuf *options; /* ptr to options mbuf */
115struct clnp_optidx *oidx; /* ptr to option index */
116struct ifnet *ifp; /* ptr to interface pkt is leaving on */
117struct 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
e5c263cf 129 opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp);
ad140953
KS
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 */
197clnp_set_opts(options, data)
198struct mbuf **options; /* target for option information */
199struct 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
e5c263cf 247 * the offset from the beginning of the mbuf data, not the
ad140953
KS
248 * actual address.
249 */
250clnp_opt_sanity(m, opts, len, oidx)
251struct mbuf *m; /* mbuf options reside in */
252caddr_t opts; /* ptr to buffer containing options */
253int len; /* length of buffer */
254struct 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
e5c263cf 347 oidx->cni_securep = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 389 oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 430 oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 466 oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 481 oidx->cni_priorp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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