mostly make EON route mtu reflect size of underlying IP route mtu
[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 $ */
587e7a0e 29/* @(#)clnp_options.c 7.7 (Berkeley) %G% */
ad140953
KS
30
31#ifndef lint
e5c263cf 32static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_options.c,v 5.1 89/02/09 16:20:37 hagens Exp $";
ad140953
KS
33#endif lint
34
35#ifdef ISO
36
e663c139
KM
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"
ad140953
KS
45
46#include "../net/if.h"
47#include "../net/route.h"
48
a50e2bc0
KS
49#include "iso.h"
50#include "clnp.h"
51#include "clnp_stat.h"
52#include "argo_debug.h"
ad140953
KS
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 */
67clnp_update_srcrt(options, oidx)
68struct mbuf *options; /* ptr to options mbuf */
69struct 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 */
114clnp_dooptions(options, oidx, ifp, isoa)
115struct mbuf *options; /* ptr to options mbuf */
116struct clnp_optidx *oidx; /* ptr to option index */
117struct ifnet *ifp; /* ptr to interface pkt is leaving on */
118struct 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 */
0358170d 128 char *rec_start; /* beginning of new rt recorded */
ad140953 129
e5c263cf 130 opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp);
ad140953 131 off = *(opt + 1);
0358170d 132 rec_start = opt + off - 1;
ad140953
KS
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) {
0358170d 145 int new_addrlen = isoa->isoa_len + 1;
ad140953
KS
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 */
0358170d 151 if (oidx->cni_recrt_len - (off - 1) < new_addrlen) {
ad140953
KS
152 *(opt + 1) = 0xff; /* terminate recording */
153 } else {
ad140953
KS
154 IFDEBUG(D_OPTIONS)
155 printf("clnp_dooptions: new addr at x%x for %d\n",
156 rec_start, new_addrlen);
157 ENDDEBUG
158
0358170d 159 bcopy((caddr_t)isoa, rec_start, new_addrlen);
ad140953
KS
160
161 /* update offset field */
0358170d 162 *(opt + 1) += new_addrlen;
ad140953
KS
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 */
188clnp_set_opts(options, data)
189struct mbuf **options; /* target for option information */
190struct 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 *
587e7a0e 207 * Also, we do not support security, priority,
ad140953 208 * nor do we allow one to send an ER option
587e7a0e
KS
209 *
210 * The QOS parameter is checked for the DECBIT.
ad140953
KS
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) ||
ad140953
KS
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
e5c263cf 239 * the offset from the beginning of the mbuf data, not the
ad140953
KS
240 * actual address.
241 */
242clnp_opt_sanity(m, opts, len, oidx)
243struct mbuf *m; /* mbuf options reside in */
244caddr_t opts; /* ptr to buffer containing options */
245int len; /* length of buffer */
246struct 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) {
0358170d 315 case CLNPOVAL_PAD:
ad140953
KS
316 /*
317 * Padding: increment pointer by length of padding
318 */
319 if (pad++) /* duplicate ? */
320 return(GEN_DUPOPT);
321 opts += oplen;
0358170d 322 break;
ad140953
KS
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
e5c263cf 339 oidx->cni_securep = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 381 oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 422 oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 458 oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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
e5c263cf 473 oidx->cni_priorp = CLNP_OPTTOOFF(m, opts);
ad140953
KS
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