xref: /original-bsd/sys/netiso/clnp_options.c (revision 982436bd)
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