xref: /csrg-svn/sys/netiso/clnp_options.c (revision 36767)
136371Ssklower /***********************************************************
236371Ssklower 		Copyright IBM Corporation 1987
336371Ssklower 
436371Ssklower                       All Rights Reserved
536371Ssklower 
636371Ssklower Permission to use, copy, modify, and distribute this software and its
736371Ssklower documentation for any purpose and without fee is hereby granted,
836371Ssklower provided that the above copyright notice appear in all copies and that
936371Ssklower both that copyright notice and this permission notice appear in
1036371Ssklower supporting documentation, and that the name of IBM not be
1136371Ssklower used in advertising or publicity pertaining to distribution of the
1236371Ssklower software without specific, written prior permission.
1336371Ssklower 
1436371Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536371Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636371Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736371Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836371Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936371Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036371Ssklower SOFTWARE.
2136371Ssklower 
2236371Ssklower ******************************************************************/
2336371Ssklower 
2436371Ssklower /*
2536371Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636371Ssklower  */
27*36767Ssklower /* $Header: /var/src/sys/netiso/RCS/clnp_options.c,v 5.1 89/02/09 16:20:37 hagens Exp $ */
28*36767Ssklower /* $Source: /var/src/sys/netiso/RCS/clnp_options.c,v $ */
2936371Ssklower 
3036371Ssklower #ifndef lint
31*36767Ssklower static char *rcsid = "$Header: /var/src/sys/netiso/RCS/clnp_options.c,v 5.1 89/02/09 16:20:37 hagens Exp $";
3236371Ssklower #endif lint
3336371Ssklower 
3436371Ssklower #ifdef ISO
3536371Ssklower 
3636371Ssklower #include "../h/types.h"
3736371Ssklower #include "../h/param.h"
3836371Ssklower #include "../h/mbuf.h"
3936371Ssklower #include "../h/domain.h"
4036371Ssklower #include "../h/protosw.h"
4136371Ssklower #include "../h/socket.h"
4236371Ssklower #include "../h/socketvar.h"
4336371Ssklower #include "../h/errno.h"
4436371Ssklower 
4536371Ssklower #include "../net/if.h"
4636371Ssklower #include "../net/route.h"
4736371Ssklower 
4836371Ssklower #include "../netiso/iso.h"
4936371Ssklower #include "../netiso/clnp.h"
5036371Ssklower #include "../netiso/clnp_stat.h"
5136371Ssklower #include "../netiso/argo_debug.h"
5236371Ssklower 
5336371Ssklower /*
5436371Ssklower  * FUNCTION:		clnp_update_srcrt
5536371Ssklower  *
5636371Ssklower  * PURPOSE:			Process src rt option accompanying a clnp datagram.
5736371Ssklower  *						- bump src route ptr if src routing and
5836371Ssklower  *							we appear current in src route list.
5936371Ssklower  *
6036371Ssklower  * RETURNS:			none
6136371Ssklower  *
6236371Ssklower  * SIDE EFFECTS:
6336371Ssklower  *
6436371Ssklower  * NOTES:			If source routing has been terminated, do nothing.
6536371Ssklower  */
6636371Ssklower clnp_update_srcrt(options, oidx)
6736371Ssklower struct mbuf			*options;	/* ptr to options mbuf */
6836371Ssklower struct clnp_optidx	*oidx;		/* ptr to option index */
6936371Ssklower {
7036371Ssklower 	u_char			len;	/* length of current address */
7136371Ssklower 	struct iso_addr	isoa;	/* copy current address into here */
7236371Ssklower 
7336371Ssklower 	if (CLNPSRCRT_TERM(oidx, options)) {
7436371Ssklower 		IFDEBUG(D_OPTIONS)
7536371Ssklower 			printf("clnp_update_srcrt: src rt terminated\n");
7636371Ssklower 		ENDDEBUG
7736371Ssklower 		return;
7836371Ssklower 	}
7936371Ssklower 
8036371Ssklower 	len = CLNPSRCRT_CLEN(oidx, options);
8136371Ssklower 	bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&isoa, len);
8236371Ssklower 	isoa.isoa_len = len;
8336371Ssklower 
8436371Ssklower 	IFDEBUG(D_OPTIONS)
8536371Ssklower 		printf("clnp_update_srcrt: current src rt: %s\n",
8636371Ssklower 			clnp_iso_addrp(&isoa));
8736371Ssklower 	ENDDEBUG
8836371Ssklower 
8936371Ssklower 	if (clnp_ours(&isoa)) {
9036371Ssklower 		IFDEBUG(D_OPTIONS)
9136371Ssklower 			printf("clnp_update_srcrt: updating src rt\n");
9236371Ssklower 		ENDDEBUG
9336371Ssklower 
9436371Ssklower 		/* update pointer to next src route */
9536371Ssklower 		len++;	/* count length byte too! */
9636371Ssklower 		CLNPSRCRT_OFF(oidx, options) += len;
9736371Ssklower 	}
9836371Ssklower }
9936371Ssklower 
10036371Ssklower /*
10136371Ssklower  * FUNCTION:		clnp_dooptions
10236371Ssklower  *
10336371Ssklower  * PURPOSE:			Process options accompanying a clnp datagram.
10436371Ssklower  *					Processing includes
10536371Ssklower  *						- log our address if recording route
10636371Ssklower  *
10736371Ssklower  * RETURNS:			none
10836371Ssklower  *
10936371Ssklower  * SIDE EFFECTS:
11036371Ssklower  *
11136371Ssklower  * NOTES:
11236371Ssklower  */
11336371Ssklower clnp_dooptions(options, oidx, ifp, isoa)
11436371Ssklower struct mbuf			*options;	/* ptr to options mbuf */
11536371Ssklower struct clnp_optidx	*oidx;		/* ptr to option index */
11636371Ssklower struct ifnet		*ifp;		/* ptr to interface pkt is leaving on */
11736371Ssklower struct iso_addr		*isoa;		/* ptr to our address for this ifp */
11836371Ssklower {
11936371Ssklower 	/*
12036371Ssklower 	 *	If record route is specified, move all
12136371Ssklower 	 *	existing records over, and insert the address of
12236371Ssklower 	 *	interface passed
12336371Ssklower 	 */
12436371Ssklower 	if (oidx->cni_recrtp) {
12536371Ssklower 		char 	*opt;			/* ptr to beginning of recrt option */
12636371Ssklower 		u_char	off;			/* offset from opt of first free byte */
12736371Ssklower 		char	*rec_start;		/* beginning of first record rt option */
12836371Ssklower 
129*36767Ssklower 		opt = CLNP_OFFTOOPT(options, oidx->cni_recrtp);
13036371Ssklower 		off = *(opt + 1);
13136371Ssklower 		rec_start = opt + 2;
13236371Ssklower 
13336371Ssklower 		IFDEBUG(D_OPTIONS)
13436371Ssklower 			printf("clnp_dooptions: record route: option x%x for %d bytes\n",
13536371Ssklower 				opt, oidx->cni_recrt_len);
13636371Ssklower 			printf("\tfree slot offset x%x\n", off);
13736371Ssklower 			printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa));
13836371Ssklower 			printf("clnp_dooptions: option dump:\n");
13936371Ssklower 			dump_buf(opt, oidx->cni_recrt_len);
14036371Ssklower 		ENDDEBUG
14136371Ssklower 
14236371Ssklower 		/* proceed only if recording has not been terminated */
14336371Ssklower 		if (off != 0xff) {
14436371Ssklower 			/*
14536371Ssklower 			 *	if there is insufficient room to store the next address,
14636371Ssklower 			 *	then terminate recording. Plus 1 on isoa_len is for the
14736371Ssklower 			 *	length byte itself
14836371Ssklower 			 */
14936371Ssklower 			if (oidx->cni_recrt_len - off < isoa->isoa_len+1) {
15036371Ssklower 				*(opt + 1) = 0xff;	/* terminate recording */
15136371Ssklower 			} else {
15236371Ssklower 				int new_addrlen = isoa->isoa_len + 1;
15336371Ssklower 				IFDEBUG(D_OPTIONS)
15436371Ssklower 					printf("clnp_dooptions: clnp_ypocb(x%x, x%x, %d)\n",
15536371Ssklower 						rec_start, rec_start + new_addrlen, off - 3);
15636371Ssklower 				ENDDEBUG
15736371Ssklower 
15836371Ssklower 				/* move existing records over */
15936371Ssklower 				clnp_ypocb(rec_start, rec_start + new_addrlen, off - 3);
16036371Ssklower 
16136371Ssklower 				IFDEBUG(D_OPTIONS)
16236371Ssklower 					printf("clnp_dooptions: new addr at x%x for %d\n",
16336371Ssklower 						rec_start, new_addrlen);
16436371Ssklower 				ENDDEBUG
16536371Ssklower 
16636371Ssklower 				/* add new record */
16736371Ssklower 				*rec_start = isoa->isoa_len;
16836371Ssklower 				bcopy((caddr_t)isoa, rec_start + 1, isoa->isoa_len);
16936371Ssklower 
17036371Ssklower 				/* update offset field */
17136371Ssklower 				*(opt + 1) = off + new_addrlen;
17236371Ssklower 
17336371Ssklower 				IFDEBUG(D_OPTIONS)
17436371Ssklower 					printf("clnp_dooptions: new option dump:\n");
17536371Ssklower 					dump_buf(opt, oidx->cni_recrt_len);
17636371Ssklower 				ENDDEBUG
17736371Ssklower 			}
17836371Ssklower 		}
17936371Ssklower 	}
18036371Ssklower }
18136371Ssklower 
18236371Ssklower /*
18336371Ssklower  * FUNCTION:		clnp_set_opts
18436371Ssklower  *
18536371Ssklower  * PURPOSE:			Check the data mbuf passed for option sanity. If it is
18636371Ssklower  *					ok, then set the options ptr to address the data mbuf.
18736371Ssklower  *					If an options mbuf exists, free it. This implies that
18836371Ssklower  *					any old options will be lost. If data is NULL, simply
18936371Ssklower  *					free any old options.
19036371Ssklower  *
19136371Ssklower  * RETURNS:			unix error code
19236371Ssklower  *
19336371Ssklower  * SIDE EFFECTS:
19436371Ssklower  *
19536371Ssklower  * NOTES:
19636371Ssklower  */
19736371Ssklower clnp_set_opts(options, data)
19836371Ssklower struct mbuf	**options;	/* target for option information */
19936371Ssklower struct mbuf	**data;		/* source of option information */
20036371Ssklower {
20136371Ssklower 	int					error = 0;	/* error return value */
20236371Ssklower 	struct clnp_optidx	dummy;		/* dummy index - not used */
20336371Ssklower 
20436371Ssklower 	/*
20536371Ssklower 	 *	remove any existing options
20636371Ssklower 	 */
20736371Ssklower 	if (*options != NULL) {
20836371Ssklower 		m_freem(*options);
20936371Ssklower 		*options = NULL;
21036371Ssklower 	}
21136371Ssklower 
21236371Ssklower 	if (*data != NULL) {
21336371Ssklower 		/*
21436371Ssklower 		 *	Insure that the options are reasonable.
21536371Ssklower 		 *
21636371Ssklower 		 *	Also, we do not support security, priority, or QOS
21736371Ssklower 		 *	nor do we allow one to send an ER option
21836371Ssklower 		 */
21936371Ssklower 		if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len,
22036371Ssklower 			&dummy) != 0) ||
22136371Ssklower 				(dummy.cni_securep) ||
22236371Ssklower 				(dummy.cni_priorp) ||
22336371Ssklower 				(dummy.cni_qos_formatp) ||
22436371Ssklower 				(dummy.cni_er_reason != ER_INVALREAS)) {
22536371Ssklower 			error = EINVAL;
22636371Ssklower 		} else {
22736371Ssklower 			*options = *data;
22836371Ssklower 			*data = NULL;	/* so caller won't free mbuf @ *data */
22936371Ssklower 		}
23036371Ssklower 	}
23136371Ssklower 	return error;
23236371Ssklower }
23336371Ssklower 
23436371Ssklower /*
23536371Ssklower  * FUNCTION:		clnp_opt_sanity
23636371Ssklower  *
23736371Ssklower  * PURPOSE:			Check the options (beginning at opts for len bytes) for
23836371Ssklower  *					sanity. In addition, fill in the option index structure
23936371Ssklower  *					in with information about each option discovered.
24036371Ssklower  *
24136371Ssklower  * RETURNS:			success (options check out) - 0
24236371Ssklower  *					failure - an ER pdu error code describing failure
24336371Ssklower  *
24436371Ssklower  * SIDE EFFECTS:
24536371Ssklower  *
24636371Ssklower  * NOTES:			Each pointer field of the option index is filled in with
247*36767Ssklower  *					the offset from the beginning of the mbuf data, not the
24836371Ssklower  *					actual address.
24936371Ssklower  */
25036371Ssklower clnp_opt_sanity(m, opts, len, oidx)
25136371Ssklower struct mbuf 		*m;		/* mbuf options reside in */
25236371Ssklower caddr_t				opts;	/* ptr to buffer containing options */
25336371Ssklower int					len;	/* length of buffer */
25436371Ssklower struct clnp_optidx	*oidx;	/* RETURN: filled in with option idx info */
25536371Ssklower {
25636371Ssklower 	u_char	opcode;			/* code of particular option */
25736371Ssklower 	u_char	oplen;			/* length of a particular option */
25836371Ssklower 	caddr_t	opts_end;		/* ptr to end of options */
25936371Ssklower 	u_char	pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0;
26036371Ssklower 							/* flags for catching duplicate options */
26136371Ssklower 
26236371Ssklower 	IFDEBUG(D_OPTIONS)
26336371Ssklower 		printf("clnp_opt_sanity: checking %d bytes of data:\n", len);
26436371Ssklower 		dump_buf(opts, len);
26536371Ssklower 	ENDDEBUG
26636371Ssklower 
26736371Ssklower 	/* clear option index field if passed */
26836371Ssklower 	bzero((caddr_t)oidx, sizeof(struct clnp_optidx));
26936371Ssklower 
27036371Ssklower 	/*
27136371Ssklower 	 *	We need to indicate whether the ER option is present. This is done
27236371Ssklower 	 *	by overloading the er_reason field to also indicate presense of
27336371Ssklower 	 *	the option along with the option value. I would like ER_INVALREAS
27436371Ssklower 	 *	to have value 0, but alas, 0 is a valid er reason...
27536371Ssklower 	 */
27636371Ssklower 	oidx->cni_er_reason = ER_INVALREAS;
27736371Ssklower 
27836371Ssklower 	opts_end = opts + len;
27936371Ssklower 	while (opts < opts_end) {
28036371Ssklower 		/* must have at least 2 bytes per option (opcode and len) */
28136371Ssklower 		if (opts + 2 > opts_end)
28236371Ssklower 			return(GEN_INCOMPLETE);
28336371Ssklower 
28436371Ssklower 		opcode = *opts++;
28536371Ssklower 		oplen = *opts++;
28636371Ssklower 		IFDEBUG(D_OPTIONS)
28736371Ssklower 			printf("clnp_opt_sanity: opcode is %x and oplen %d\n",
28836371Ssklower 				opcode, oplen);
28936371Ssklower 			printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT);
29036371Ssklower 
29136371Ssklower 				switch (opcode) {
29236371Ssklower 					case CLNPOVAL_PAD: {
29336371Ssklower 						printf("CLNPOVAL_PAD\n");
29436371Ssklower 					} break;
29536371Ssklower 					case CLNPOVAL_SECURE: {
29636371Ssklower 						printf("CLNPOVAL_SECURE\n");
29736371Ssklower 					} break;
29836371Ssklower 					case CLNPOVAL_SRCRT: {
29936371Ssklower 							printf("CLNPOVAL_SRCRT\n");
30036371Ssklower 					} break;
30136371Ssklower 					case CLNPOVAL_RECRT: {
30236371Ssklower 						printf("CLNPOVAL_RECRT\n");
30336371Ssklower 					} break;
30436371Ssklower 					case CLNPOVAL_QOS: {
30536371Ssklower 						printf("CLNPOVAL_QOS\n");
30636371Ssklower 					} break;
30736371Ssklower 					case CLNPOVAL_PRIOR: {
30836371Ssklower 						printf("CLNPOVAL_PRIOR\n");
30936371Ssklower 					} break;
31036371Ssklower 					case CLNPOVAL_ERREAS: {
31136371Ssklower 						printf("CLNPOVAL_ERREAS\n");
31236371Ssklower 					} break;
31336371Ssklower 					default:
31436371Ssklower 						printf("UKNOWN option %x\n", opcode);
31536371Ssklower 				}
31636371Ssklower 		ENDDEBUG
31736371Ssklower 
31836371Ssklower 		/* don't allow crazy length values */
31936371Ssklower 		if (opts + oplen > opts_end)
32036371Ssklower 			return(GEN_INCOMPLETE);
32136371Ssklower 
32236371Ssklower 		switch (opcode) {
32336371Ssklower 			case CLNPOVAL_PAD: {
32436371Ssklower 				/*
32536371Ssklower 				 *	Padding: increment pointer by length of padding
32636371Ssklower 				 */
32736371Ssklower 				if (pad++)						/* duplicate ? */
32836371Ssklower 					return(GEN_DUPOPT);
32936371Ssklower 				opts += oplen;
33036371Ssklower 			} break;
33136371Ssklower 
33236371Ssklower 			case CLNPOVAL_SECURE: {
33336371Ssklower 				u_char	format = *opts;
33436371Ssklower 
33536371Ssklower 				if (secure++)					/* duplicate ? */
33636371Ssklower 					return(GEN_DUPOPT);
33736371Ssklower 				/*
33836371Ssklower 				 *	Security: high 2 bits of first octet indicate format
33936371Ssklower 				 *	(00 in high bits is reserved).
34036371Ssklower 				 *	Remaining bits must be 0. Remaining octets indicate
34136371Ssklower 				 *	actual security
34236371Ssklower 				 */
34336371Ssklower 				if (((format & 0x3f) > 0) ||	/* low 6 bits set ? */
34436371Ssklower 					((format & 0xc0) == 0))		/* high 2 bits zero ? */
34536371Ssklower 					return(GEN_HDRSYNTAX);
34636371Ssklower 
347*36767Ssklower 				oidx->cni_securep = CLNP_OPTTOOFF(m, opts);
34836371Ssklower 				oidx->cni_secure_len = oplen;
34936371Ssklower 				opts += oplen;
35036371Ssklower 			} break;
35136371Ssklower 
35236371Ssklower 			case CLNPOVAL_SRCRT: {
35336371Ssklower 				u_char	type, offset;	/* type of rt, offset of start */
35436371Ssklower 				caddr_t	route_end;		/* address of end of route option */
35536371Ssklower 
35636371Ssklower 				IFDEBUG(D_OPTIONS)
35736371Ssklower 					printf("clnp_opt_sanity: SRC RT\n");
35836371Ssklower 				ENDDEBUG
35936371Ssklower 
36036371Ssklower 				if (srcrt++)					/* duplicate ? */
36136371Ssklower 					return(GEN_DUPOPT);
36236371Ssklower 				/*
36336371Ssklower 				 *	source route: There must be 2 bytes following the length
36436371Ssklower 				 *	field: type and offset. The type must be either
36536371Ssklower 				 *	partial route or complete route. The offset field must
36636371Ssklower 				 *	be within the option. A single exception is made, however.
36736371Ssklower 				 *	The offset may be 1 greater than the length. This case
36836371Ssklower 				 *	occurs when the last source route record is consumed.
36936371Ssklower 				 *	In this case, we ignore the source route option.
37036371Ssklower 				 *	RAH? You should be able to set offset to 'ff' like in record
37136371Ssklower 				 *	route!
37236371Ssklower 				 *	Following this is a series of address fields.
37336371Ssklower 				 *	Each address field is composed of a (length, address) pair.
37436371Ssklower 				 *	Insure that the offset and each address length is reasonable
37536371Ssklower 				 */
37636371Ssklower 				route_end = opts + oplen;
37736371Ssklower 
37836371Ssklower 				if (opts + 2 > route_end)
37936371Ssklower 					return(SRCRT_SYNTAX);
38036371Ssklower 
38136371Ssklower 				type = *opts;
38236371Ssklower 				offset = *(opts+1);
38336371Ssklower 
38436371Ssklower 
38536371Ssklower 				/* type must be partial or complete */
38636371Ssklower 				if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
38736371Ssklower 					return(SRCRT_SYNTAX);
38836371Ssklower 
389*36767Ssklower 				oidx->cni_srcrt_s = CLNP_OPTTOOFF(m, opts);
39036371Ssklower 				oidx->cni_srcrt_len = oplen;
39136371Ssklower 
39236371Ssklower 				opts += offset-1;	/*set opts to first addr in rt */
39336371Ssklower 
39436371Ssklower 				/*
39536371Ssklower 				 *	Offset must be reasonable:
39636371Ssklower 				 *	less than end of options, or equal to end of options
39736371Ssklower 				 */
39836371Ssklower 				if (opts >= route_end) {
39936371Ssklower 					if (opts == route_end) {
40036371Ssklower 						IFDEBUG(D_OPTIONS)
40136371Ssklower 							printf("clnp_opt_sanity: end of src route info\n");
40236371Ssklower 						ENDDEBUG
40336371Ssklower 						break;
40436371Ssklower 					} else
40536371Ssklower 						return(SRCRT_SYNTAX);
40636371Ssklower 				}
40736371Ssklower 
40836371Ssklower 				while (opts < route_end) {
40936371Ssklower 					u_char	addrlen = *opts++;
41036371Ssklower 					if (opts + addrlen > route_end)
41136371Ssklower 						return(SRCRT_SYNTAX);
41236371Ssklower 					opts += addrlen;
41336371Ssklower 				}
41436371Ssklower 			} break;
41536371Ssklower 			case CLNPOVAL_RECRT: {
41636371Ssklower 				u_char	type, offset;	/* type of rt, offset of start */
41736371Ssklower 				caddr_t	record_end;		/* address of end of record option */
41836371Ssklower 
41936371Ssklower 				if (recrt++)					/* duplicate ? */
42036371Ssklower 					return(GEN_DUPOPT);
42136371Ssklower 				/*
42236371Ssklower 				 *	record route: after the length field, expect a
42336371Ssklower 				 *	type and offset. Type must be partial or complete.
42436371Ssklower 				 *	Offset indicates where to start recording. Insure it
42536371Ssklower 				 *	is within the option. All ones for offset means
42636371Ssklower 				 *	recording is terminated.
42736371Ssklower 				 */
42836371Ssklower 				record_end = opts + oplen;
42936371Ssklower 
430*36767Ssklower 				oidx->cni_recrtp = CLNP_OPTTOOFF(m, opts);
43136371Ssklower 				oidx->cni_recrt_len = oplen;
43236371Ssklower 
43336371Ssklower 				if (opts + 2 > record_end)
43436371Ssklower 					return(GEN_INCOMPLETE);
43536371Ssklower 
43636371Ssklower 				type = *opts;
43736371Ssklower 				offset = *(opts+1);
43836371Ssklower 
43936371Ssklower 				/* type must be partial or complete */
44036371Ssklower 				if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
44136371Ssklower 					return(GEN_HDRSYNTAX);
44236371Ssklower 
44336371Ssklower 				/* offset must be reasonable */
44436371Ssklower 				if ((offset < 0xff) && (opts + offset > record_end))
44536371Ssklower 					return(GEN_HDRSYNTAX);
44636371Ssklower 				opts += oplen;
44736371Ssklower 			} break;
44836371Ssklower 			case CLNPOVAL_QOS: {
44936371Ssklower 				u_char	format = *opts;
45036371Ssklower 
45136371Ssklower 				if (qos++)					/* duplicate ? */
45236371Ssklower 					return(GEN_DUPOPT);
45336371Ssklower 				/*
45436371Ssklower 				 *	qos: high 2 bits of first octet indicate format
45536371Ssklower 				 *	(00 in high bits is reserved).
45636371Ssklower 				 *	Remaining bits must be 0 (unless format indicates
45736371Ssklower 				 *	globally unique qos, in which case remaining bits indicate
45836371Ssklower 				 *	qos (except bit 6 which is reserved)).  Otherwise,
45936371Ssklower 				 *	remaining octets indicate actual qos.
46036371Ssklower 				 */
46136371Ssklower 				if (((format & 0xc0) == 0) ||	/* high 2 bits zero ? */
46236371Ssklower 					(((format & 0xc0) != CLNPOVAL_GLOBAL) &&
46336371Ssklower 						((format & 0x3f) > 0))) /* not global,low bits used ? */
46436371Ssklower 					return(GEN_HDRSYNTAX);
46536371Ssklower 
466*36767Ssklower 				oidx->cni_qos_formatp = CLNP_OPTTOOFF(m, opts);
46736371Ssklower 				oidx->cni_qos_len = oplen;
46836371Ssklower 
46936371Ssklower 				opts += oplen;
47036371Ssklower 			} break;
47136371Ssklower 
47236371Ssklower 			case CLNPOVAL_PRIOR: {
47336371Ssklower 				if (prior++)				/* duplicate ? */
47436371Ssklower 					return(GEN_DUPOPT);
47536371Ssklower 				/*
47636371Ssklower 				 *	priority: value must be one byte long
47736371Ssklower 				 */
47836371Ssklower 				if (oplen != 1)
47936371Ssklower 					return(GEN_HDRSYNTAX);
48036371Ssklower 
481*36767Ssklower 				oidx->cni_priorp = CLNP_OPTTOOFF(m, opts);
48236371Ssklower 
48336371Ssklower 				opts += oplen;
48436371Ssklower 			} break;
48536371Ssklower 
48636371Ssklower 			case CLNPOVAL_ERREAS: {
48736371Ssklower 				/*
48836371Ssklower 				 *	er reason: value must be two bytes long
48936371Ssklower 				 */
49036371Ssklower 				if (oplen != 2)
49136371Ssklower 					return(GEN_HDRSYNTAX);
49236371Ssklower 
49336371Ssklower 				oidx->cni_er_reason = *opts;
49436371Ssklower 
49536371Ssklower 				opts += oplen;
49636371Ssklower 			} break;
49736371Ssklower 
49836371Ssklower 			default: {
49936371Ssklower 				IFDEBUG(D_OPTIONS)
50036371Ssklower 					printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode);
50136371Ssklower 				ENDDEBUG
50236371Ssklower 				return(DISC_UNSUPPOPT);
50336371Ssklower 			}
50436371Ssklower 		}
50536371Ssklower 	}
50636371Ssklower 		IFDEBUG(D_OPTIONS)
50736371Ssklower 			printf("clnp_opt_sanity: return(0)\n", opcode);
50836371Ssklower 		ENDDEBUG
50936371Ssklower 	return(0);
51036371Ssklower }
51136371Ssklower #endif	ISO
512