xref: /csrg-svn/sys/netiso/clnp_options.c (revision 36371)
1*36371Ssklower /***********************************************************
2*36371Ssklower 		Copyright IBM Corporation 1987
3*36371Ssklower 
4*36371Ssklower                       All Rights Reserved
5*36371Ssklower 
6*36371Ssklower Permission to use, copy, modify, and distribute this software and its
7*36371Ssklower documentation for any purpose and without fee is hereby granted,
8*36371Ssklower provided that the above copyright notice appear in all copies and that
9*36371Ssklower both that copyright notice and this permission notice appear in
10*36371Ssklower supporting documentation, and that the name of IBM not be
11*36371Ssklower used in advertising or publicity pertaining to distribution of the
12*36371Ssklower software without specific, written prior permission.
13*36371Ssklower 
14*36371Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36371Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36371Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36371Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36371Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36371Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36371Ssklower SOFTWARE.
21*36371Ssklower 
22*36371Ssklower ******************************************************************/
23*36371Ssklower 
24*36371Ssklower /*
25*36371Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36371Ssklower  */
27*36371Ssklower /* $Header: clnp_options.c,v 4.3 88/09/15 18:57:36 hagens Exp $ */
28*36371Ssklower /* $Source: /usr/argo/sys/netiso/RCS/clnp_options.c,v $ */
29*36371Ssklower 
30*36371Ssklower #ifndef lint
31*36371Ssklower static char *rcsid = "$Header: clnp_options.c,v 4.3 88/09/15 18:57:36 hagens Exp $";
32*36371Ssklower #endif lint
33*36371Ssklower 
34*36371Ssklower #ifdef ISO
35*36371Ssklower 
36*36371Ssklower #include "../h/types.h"
37*36371Ssklower #include "../h/param.h"
38*36371Ssklower #include "../h/mbuf.h"
39*36371Ssklower #include "../h/domain.h"
40*36371Ssklower #include "../h/protosw.h"
41*36371Ssklower #include "../h/socket.h"
42*36371Ssklower #include "../h/socketvar.h"
43*36371Ssklower #include "../h/errno.h"
44*36371Ssklower 
45*36371Ssklower #include "../net/if.h"
46*36371Ssklower #include "../net/route.h"
47*36371Ssklower 
48*36371Ssklower #include "../netiso/iso.h"
49*36371Ssklower #include "../netiso/clnp.h"
50*36371Ssklower #include "../netiso/clnp_stat.h"
51*36371Ssklower #include "../netiso/argo_debug.h"
52*36371Ssklower 
53*36371Ssklower /*
54*36371Ssklower  * FUNCTION:		clnp_update_srcrt
55*36371Ssklower  *
56*36371Ssklower  * PURPOSE:			Process src rt option accompanying a clnp datagram.
57*36371Ssklower  *						- bump src route ptr if src routing and
58*36371Ssklower  *							we appear current in src route list.
59*36371Ssklower  *
60*36371Ssklower  * RETURNS:			none
61*36371Ssklower  *
62*36371Ssklower  * SIDE EFFECTS:
63*36371Ssklower  *
64*36371Ssklower  * NOTES:			If source routing has been terminated, do nothing.
65*36371Ssklower  */
66*36371Ssklower clnp_update_srcrt(options, oidx)
67*36371Ssklower struct mbuf			*options;	/* ptr to options mbuf */
68*36371Ssklower struct clnp_optidx	*oidx;		/* ptr to option index */
69*36371Ssklower {
70*36371Ssklower 	u_char			len;	/* length of current address */
71*36371Ssklower 	struct iso_addr	isoa;	/* copy current address into here */
72*36371Ssklower 
73*36371Ssklower 	if (CLNPSRCRT_TERM(oidx, options)) {
74*36371Ssklower 		IFDEBUG(D_OPTIONS)
75*36371Ssklower 			printf("clnp_update_srcrt: src rt terminated\n");
76*36371Ssklower 		ENDDEBUG
77*36371Ssklower 		return;
78*36371Ssklower 	}
79*36371Ssklower 
80*36371Ssklower 	len = CLNPSRCRT_CLEN(oidx, options);
81*36371Ssklower 	bcopy(CLNPSRCRT_CADDR(oidx, options), (caddr_t)&isoa, len);
82*36371Ssklower 	isoa.isoa_len = len;
83*36371Ssklower 
84*36371Ssklower 	IFDEBUG(D_OPTIONS)
85*36371Ssklower 		printf("clnp_update_srcrt: current src rt: %s\n",
86*36371Ssklower 			clnp_iso_addrp(&isoa));
87*36371Ssklower 	ENDDEBUG
88*36371Ssklower 
89*36371Ssklower 	if (clnp_ours(&isoa)) {
90*36371Ssklower 		IFDEBUG(D_OPTIONS)
91*36371Ssklower 			printf("clnp_update_srcrt: updating src rt\n");
92*36371Ssklower 		ENDDEBUG
93*36371Ssklower 
94*36371Ssklower 		/* update pointer to next src route */
95*36371Ssklower 		len++;	/* count length byte too! */
96*36371Ssklower 		CLNPSRCRT_OFF(oidx, options) += len;
97*36371Ssklower 	}
98*36371Ssklower }
99*36371Ssklower 
100*36371Ssklower /*
101*36371Ssklower  * FUNCTION:		clnp_dooptions
102*36371Ssklower  *
103*36371Ssklower  * PURPOSE:			Process options accompanying a clnp datagram.
104*36371Ssklower  *					Processing includes
105*36371Ssklower  *						- log our address if recording route
106*36371Ssklower  *
107*36371Ssklower  * RETURNS:			none
108*36371Ssklower  *
109*36371Ssklower  * SIDE EFFECTS:
110*36371Ssklower  *
111*36371Ssklower  * NOTES:
112*36371Ssklower  */
113*36371Ssklower clnp_dooptions(options, oidx, ifp, isoa)
114*36371Ssklower struct mbuf			*options;	/* ptr to options mbuf */
115*36371Ssklower struct clnp_optidx	*oidx;		/* ptr to option index */
116*36371Ssklower struct ifnet		*ifp;		/* ptr to interface pkt is leaving on */
117*36371Ssklower struct iso_addr		*isoa;		/* ptr to our address for this ifp */
118*36371Ssklower {
119*36371Ssklower 	/*
120*36371Ssklower 	 *	If record route is specified, move all
121*36371Ssklower 	 *	existing records over, and insert the address of
122*36371Ssklower 	 *	interface passed
123*36371Ssklower 	 */
124*36371Ssklower 	if (oidx->cni_recrtp) {
125*36371Ssklower 		char 	*opt;			/* ptr to beginning of recrt option */
126*36371Ssklower 		u_char	off;			/* offset from opt of first free byte */
127*36371Ssklower 		char	*rec_start;		/* beginning of first record rt option */
128*36371Ssklower 
129*36371Ssklower 		opt = oidx->cni_recrtp + (caddr_t)options;
130*36371Ssklower 		off = *(opt + 1);
131*36371Ssklower 		rec_start = opt + 2;
132*36371Ssklower 
133*36371Ssklower 		IFDEBUG(D_OPTIONS)
134*36371Ssklower 			printf("clnp_dooptions: record route: option x%x for %d bytes\n",
135*36371Ssklower 				opt, oidx->cni_recrt_len);
136*36371Ssklower 			printf("\tfree slot offset x%x\n", off);
137*36371Ssklower 			printf("clnp_dooptions: recording %s\n", clnp_iso_addrp(isoa));
138*36371Ssklower 			printf("clnp_dooptions: option dump:\n");
139*36371Ssklower 			dump_buf(opt, oidx->cni_recrt_len);
140*36371Ssklower 		ENDDEBUG
141*36371Ssklower 
142*36371Ssklower 		/* proceed only if recording has not been terminated */
143*36371Ssklower 		if (off != 0xff) {
144*36371Ssklower 			/*
145*36371Ssklower 			 *	if there is insufficient room to store the next address,
146*36371Ssklower 			 *	then terminate recording. Plus 1 on isoa_len is for the
147*36371Ssklower 			 *	length byte itself
148*36371Ssklower 			 */
149*36371Ssklower 			if (oidx->cni_recrt_len - off < isoa->isoa_len+1) {
150*36371Ssklower 				*(opt + 1) = 0xff;	/* terminate recording */
151*36371Ssklower 			} else {
152*36371Ssklower 				int new_addrlen = isoa->isoa_len + 1;
153*36371Ssklower 				IFDEBUG(D_OPTIONS)
154*36371Ssklower 					printf("clnp_dooptions: clnp_ypocb(x%x, x%x, %d)\n",
155*36371Ssklower 						rec_start, rec_start + new_addrlen, off - 3);
156*36371Ssklower 				ENDDEBUG
157*36371Ssklower 
158*36371Ssklower 				/* move existing records over */
159*36371Ssklower 				clnp_ypocb(rec_start, rec_start + new_addrlen, off - 3);
160*36371Ssklower 
161*36371Ssklower 				IFDEBUG(D_OPTIONS)
162*36371Ssklower 					printf("clnp_dooptions: new addr at x%x for %d\n",
163*36371Ssklower 						rec_start, new_addrlen);
164*36371Ssklower 				ENDDEBUG
165*36371Ssklower 
166*36371Ssklower 				/* add new record */
167*36371Ssklower 				*rec_start = isoa->isoa_len;
168*36371Ssklower 				bcopy((caddr_t)isoa, rec_start + 1, isoa->isoa_len);
169*36371Ssklower 
170*36371Ssklower 				/* update offset field */
171*36371Ssklower 				*(opt + 1) = off + new_addrlen;
172*36371Ssklower 
173*36371Ssklower 				IFDEBUG(D_OPTIONS)
174*36371Ssklower 					printf("clnp_dooptions: new option dump:\n");
175*36371Ssklower 					dump_buf(opt, oidx->cni_recrt_len);
176*36371Ssklower 				ENDDEBUG
177*36371Ssklower 			}
178*36371Ssklower 		}
179*36371Ssklower 	}
180*36371Ssklower }
181*36371Ssklower 
182*36371Ssklower /*
183*36371Ssklower  * FUNCTION:		clnp_set_opts
184*36371Ssklower  *
185*36371Ssklower  * PURPOSE:			Check the data mbuf passed for option sanity. If it is
186*36371Ssklower  *					ok, then set the options ptr to address the data mbuf.
187*36371Ssklower  *					If an options mbuf exists, free it. This implies that
188*36371Ssklower  *					any old options will be lost. If data is NULL, simply
189*36371Ssklower  *					free any old options.
190*36371Ssklower  *
191*36371Ssklower  * RETURNS:			unix error code
192*36371Ssklower  *
193*36371Ssklower  * SIDE EFFECTS:
194*36371Ssklower  *
195*36371Ssklower  * NOTES:
196*36371Ssklower  */
197*36371Ssklower clnp_set_opts(options, data)
198*36371Ssklower struct mbuf	**options;	/* target for option information */
199*36371Ssklower struct mbuf	**data;		/* source of option information */
200*36371Ssklower {
201*36371Ssklower 	int					error = 0;	/* error return value */
202*36371Ssklower 	struct clnp_optidx	dummy;		/* dummy index - not used */
203*36371Ssklower 
204*36371Ssklower 	/*
205*36371Ssklower 	 *	remove any existing options
206*36371Ssklower 	 */
207*36371Ssklower 	if (*options != NULL) {
208*36371Ssklower 		m_freem(*options);
209*36371Ssklower 		*options = NULL;
210*36371Ssklower 	}
211*36371Ssklower 
212*36371Ssklower 	if (*data != NULL) {
213*36371Ssklower 		/*
214*36371Ssklower 		 *	Insure that the options are reasonable.
215*36371Ssklower 		 *
216*36371Ssklower 		 *	Also, we do not support security, priority, or QOS
217*36371Ssklower 		 *	nor do we allow one to send an ER option
218*36371Ssklower 		 */
219*36371Ssklower 		if ((clnp_opt_sanity(*data, mtod(*data, caddr_t), (*data)->m_len,
220*36371Ssklower 			&dummy) != 0) ||
221*36371Ssklower 				(dummy.cni_securep) ||
222*36371Ssklower 				(dummy.cni_priorp) ||
223*36371Ssklower 				(dummy.cni_qos_formatp) ||
224*36371Ssklower 				(dummy.cni_er_reason != ER_INVALREAS)) {
225*36371Ssklower 			error = EINVAL;
226*36371Ssklower 		} else {
227*36371Ssklower 			*options = *data;
228*36371Ssklower 			*data = NULL;	/* so caller won't free mbuf @ *data */
229*36371Ssklower 		}
230*36371Ssklower 	}
231*36371Ssklower 	return error;
232*36371Ssklower }
233*36371Ssklower 
234*36371Ssklower /*
235*36371Ssklower  * FUNCTION:		clnp_opt_sanity
236*36371Ssklower  *
237*36371Ssklower  * PURPOSE:			Check the options (beginning at opts for len bytes) for
238*36371Ssklower  *					sanity. In addition, fill in the option index structure
239*36371Ssklower  *					in with information about each option discovered.
240*36371Ssklower  *
241*36371Ssklower  * RETURNS:			success (options check out) - 0
242*36371Ssklower  *					failure - an ER pdu error code describing failure
243*36371Ssklower  *
244*36371Ssklower  * SIDE EFFECTS:
245*36371Ssklower  *
246*36371Ssklower  * NOTES:			Each pointer field of the option index is filled in with
247*36371Ssklower  *					the offset from the beginning of the mbuf, not the
248*36371Ssklower  *					actual address.
249*36371Ssklower  */
250*36371Ssklower clnp_opt_sanity(m, opts, len, oidx)
251*36371Ssklower struct mbuf 		*m;		/* mbuf options reside in */
252*36371Ssklower caddr_t				opts;	/* ptr to buffer containing options */
253*36371Ssklower int					len;	/* length of buffer */
254*36371Ssklower struct clnp_optidx	*oidx;	/* RETURN: filled in with option idx info */
255*36371Ssklower {
256*36371Ssklower 	u_char	opcode;			/* code of particular option */
257*36371Ssklower 	u_char	oplen;			/* length of a particular option */
258*36371Ssklower 	caddr_t	opts_end;		/* ptr to end of options */
259*36371Ssklower 	u_char	pad = 0, secure = 0, srcrt = 0, recrt = 0, qos = 0, prior = 0;
260*36371Ssklower 							/* flags for catching duplicate options */
261*36371Ssklower 
262*36371Ssklower 	IFDEBUG(D_OPTIONS)
263*36371Ssklower 		printf("clnp_opt_sanity: checking %d bytes of data:\n", len);
264*36371Ssklower 		dump_buf(opts, len);
265*36371Ssklower 	ENDDEBUG
266*36371Ssklower 
267*36371Ssklower 	/* clear option index field if passed */
268*36371Ssklower 	bzero((caddr_t)oidx, sizeof(struct clnp_optidx));
269*36371Ssklower 
270*36371Ssklower 	/*
271*36371Ssklower 	 *	We need to indicate whether the ER option is present. This is done
272*36371Ssklower 	 *	by overloading the er_reason field to also indicate presense of
273*36371Ssklower 	 *	the option along with the option value. I would like ER_INVALREAS
274*36371Ssklower 	 *	to have value 0, but alas, 0 is a valid er reason...
275*36371Ssklower 	 */
276*36371Ssklower 	oidx->cni_er_reason = ER_INVALREAS;
277*36371Ssklower 
278*36371Ssklower 	opts_end = opts + len;
279*36371Ssklower 	while (opts < opts_end) {
280*36371Ssklower 		/* must have at least 2 bytes per option (opcode and len) */
281*36371Ssklower 		if (opts + 2 > opts_end)
282*36371Ssklower 			return(GEN_INCOMPLETE);
283*36371Ssklower 
284*36371Ssklower 		opcode = *opts++;
285*36371Ssklower 		oplen = *opts++;
286*36371Ssklower 		IFDEBUG(D_OPTIONS)
287*36371Ssklower 			printf("clnp_opt_sanity: opcode is %x and oplen %d\n",
288*36371Ssklower 				opcode, oplen);
289*36371Ssklower 			printf("clnp_opt_sanity: clnpoval_SRCRT is %x\n", CLNPOVAL_SRCRT);
290*36371Ssklower 
291*36371Ssklower 				switch (opcode) {
292*36371Ssklower 					case CLNPOVAL_PAD: {
293*36371Ssklower 						printf("CLNPOVAL_PAD\n");
294*36371Ssklower 					} break;
295*36371Ssklower 					case CLNPOVAL_SECURE: {
296*36371Ssklower 						printf("CLNPOVAL_SECURE\n");
297*36371Ssklower 					} break;
298*36371Ssklower 					case CLNPOVAL_SRCRT: {
299*36371Ssklower 							printf("CLNPOVAL_SRCRT\n");
300*36371Ssklower 					} break;
301*36371Ssklower 					case CLNPOVAL_RECRT: {
302*36371Ssklower 						printf("CLNPOVAL_RECRT\n");
303*36371Ssklower 					} break;
304*36371Ssklower 					case CLNPOVAL_QOS: {
305*36371Ssklower 						printf("CLNPOVAL_QOS\n");
306*36371Ssklower 					} break;
307*36371Ssklower 					case CLNPOVAL_PRIOR: {
308*36371Ssklower 						printf("CLNPOVAL_PRIOR\n");
309*36371Ssklower 					} break;
310*36371Ssklower 					case CLNPOVAL_ERREAS: {
311*36371Ssklower 						printf("CLNPOVAL_ERREAS\n");
312*36371Ssklower 					} break;
313*36371Ssklower 					default:
314*36371Ssklower 						printf("UKNOWN option %x\n", opcode);
315*36371Ssklower 				}
316*36371Ssklower 		ENDDEBUG
317*36371Ssklower 
318*36371Ssklower 		/* don't allow crazy length values */
319*36371Ssklower 		if (opts + oplen > opts_end)
320*36371Ssklower 			return(GEN_INCOMPLETE);
321*36371Ssklower 
322*36371Ssklower 		switch (opcode) {
323*36371Ssklower 			case CLNPOVAL_PAD: {
324*36371Ssklower 				/*
325*36371Ssklower 				 *	Padding: increment pointer by length of padding
326*36371Ssklower 				 */
327*36371Ssklower 				if (pad++)						/* duplicate ? */
328*36371Ssklower 					return(GEN_DUPOPT);
329*36371Ssklower 				opts += oplen;
330*36371Ssklower 			} break;
331*36371Ssklower 
332*36371Ssklower 			case CLNPOVAL_SECURE: {
333*36371Ssklower 				u_char	format = *opts;
334*36371Ssklower 
335*36371Ssklower 				if (secure++)					/* duplicate ? */
336*36371Ssklower 					return(GEN_DUPOPT);
337*36371Ssklower 				/*
338*36371Ssklower 				 *	Security: high 2 bits of first octet indicate format
339*36371Ssklower 				 *	(00 in high bits is reserved).
340*36371Ssklower 				 *	Remaining bits must be 0. Remaining octets indicate
341*36371Ssklower 				 *	actual security
342*36371Ssklower 				 */
343*36371Ssklower 				if (((format & 0x3f) > 0) ||	/* low 6 bits set ? */
344*36371Ssklower 					((format & 0xc0) == 0))		/* high 2 bits zero ? */
345*36371Ssklower 					return(GEN_HDRSYNTAX);
346*36371Ssklower 
347*36371Ssklower 				oidx->cni_securep = opts - (caddr_t)m;
348*36371Ssklower 				oidx->cni_secure_len = oplen;
349*36371Ssklower 				opts += oplen;
350*36371Ssklower 			} break;
351*36371Ssklower 
352*36371Ssklower 			case CLNPOVAL_SRCRT: {
353*36371Ssklower 				u_char	type, offset;	/* type of rt, offset of start */
354*36371Ssklower 				caddr_t	route_end;		/* address of end of route option */
355*36371Ssklower 
356*36371Ssklower 				IFDEBUG(D_OPTIONS)
357*36371Ssklower 					printf("clnp_opt_sanity: SRC RT\n");
358*36371Ssklower 				ENDDEBUG
359*36371Ssklower 
360*36371Ssklower 				if (srcrt++)					/* duplicate ? */
361*36371Ssklower 					return(GEN_DUPOPT);
362*36371Ssklower 				/*
363*36371Ssklower 				 *	source route: There must be 2 bytes following the length
364*36371Ssklower 				 *	field: type and offset. The type must be either
365*36371Ssklower 				 *	partial route or complete route. The offset field must
366*36371Ssklower 				 *	be within the option. A single exception is made, however.
367*36371Ssklower 				 *	The offset may be 1 greater than the length. This case
368*36371Ssklower 				 *	occurs when the last source route record is consumed.
369*36371Ssklower 				 *	In this case, we ignore the source route option.
370*36371Ssklower 				 *	RAH? You should be able to set offset to 'ff' like in record
371*36371Ssklower 				 *	route!
372*36371Ssklower 				 *	Following this is a series of address fields.
373*36371Ssklower 				 *	Each address field is composed of a (length, address) pair.
374*36371Ssklower 				 *	Insure that the offset and each address length is reasonable
375*36371Ssklower 				 */
376*36371Ssklower 				route_end = opts + oplen;
377*36371Ssklower 
378*36371Ssklower 				if (opts + 2 > route_end)
379*36371Ssklower 					return(SRCRT_SYNTAX);
380*36371Ssklower 
381*36371Ssklower 				type = *opts;
382*36371Ssklower 				offset = *(opts+1);
383*36371Ssklower 
384*36371Ssklower 
385*36371Ssklower 				/* type must be partial or complete */
386*36371Ssklower 				if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
387*36371Ssklower 					return(SRCRT_SYNTAX);
388*36371Ssklower 
389*36371Ssklower 				oidx->cni_srcrt_s = opts - (caddr_t)m;
390*36371Ssklower 				oidx->cni_srcrt_len = oplen;
391*36371Ssklower 
392*36371Ssklower 				opts += offset-1;	/*set opts to first addr in rt */
393*36371Ssklower 
394*36371Ssklower 				/*
395*36371Ssklower 				 *	Offset must be reasonable:
396*36371Ssklower 				 *	less than end of options, or equal to end of options
397*36371Ssklower 				 */
398*36371Ssklower 				if (opts >= route_end) {
399*36371Ssklower 					if (opts == route_end) {
400*36371Ssklower 						IFDEBUG(D_OPTIONS)
401*36371Ssklower 							printf("clnp_opt_sanity: end of src route info\n");
402*36371Ssklower 						ENDDEBUG
403*36371Ssklower 						break;
404*36371Ssklower 					} else
405*36371Ssklower 						return(SRCRT_SYNTAX);
406*36371Ssklower 				}
407*36371Ssklower 
408*36371Ssklower 				while (opts < route_end) {
409*36371Ssklower 					u_char	addrlen = *opts++;
410*36371Ssklower 					if (opts + addrlen > route_end)
411*36371Ssklower 						return(SRCRT_SYNTAX);
412*36371Ssklower 					opts += addrlen;
413*36371Ssklower 				}
414*36371Ssklower 			} break;
415*36371Ssklower 			case CLNPOVAL_RECRT: {
416*36371Ssklower 				u_char	type, offset;	/* type of rt, offset of start */
417*36371Ssklower 				caddr_t	record_end;		/* address of end of record option */
418*36371Ssklower 
419*36371Ssklower 				if (recrt++)					/* duplicate ? */
420*36371Ssklower 					return(GEN_DUPOPT);
421*36371Ssklower 				/*
422*36371Ssklower 				 *	record route: after the length field, expect a
423*36371Ssklower 				 *	type and offset. Type must be partial or complete.
424*36371Ssklower 				 *	Offset indicates where to start recording. Insure it
425*36371Ssklower 				 *	is within the option. All ones for offset means
426*36371Ssklower 				 *	recording is terminated.
427*36371Ssklower 				 */
428*36371Ssklower 				record_end = opts + oplen;
429*36371Ssklower 
430*36371Ssklower 				oidx->cni_recrtp = opts - (caddr_t)m;
431*36371Ssklower 				oidx->cni_recrt_len = oplen;
432*36371Ssklower 
433*36371Ssklower 				if (opts + 2 > record_end)
434*36371Ssklower 					return(GEN_INCOMPLETE);
435*36371Ssklower 
436*36371Ssklower 				type = *opts;
437*36371Ssklower 				offset = *(opts+1);
438*36371Ssklower 
439*36371Ssklower 				/* type must be partial or complete */
440*36371Ssklower 				if (!((type == CLNPOVAL_PARTRT) || (type == CLNPOVAL_COMPRT)))
441*36371Ssklower 					return(GEN_HDRSYNTAX);
442*36371Ssklower 
443*36371Ssklower 				/* offset must be reasonable */
444*36371Ssklower 				if ((offset < 0xff) && (opts + offset > record_end))
445*36371Ssklower 					return(GEN_HDRSYNTAX);
446*36371Ssklower 				opts += oplen;
447*36371Ssklower 			} break;
448*36371Ssklower 			case CLNPOVAL_QOS: {
449*36371Ssklower 				u_char	format = *opts;
450*36371Ssklower 
451*36371Ssklower 				if (qos++)					/* duplicate ? */
452*36371Ssklower 					return(GEN_DUPOPT);
453*36371Ssklower 				/*
454*36371Ssklower 				 *	qos: high 2 bits of first octet indicate format
455*36371Ssklower 				 *	(00 in high bits is reserved).
456*36371Ssklower 				 *	Remaining bits must be 0 (unless format indicates
457*36371Ssklower 				 *	globally unique qos, in which case remaining bits indicate
458*36371Ssklower 				 *	qos (except bit 6 which is reserved)).  Otherwise,
459*36371Ssklower 				 *	remaining octets indicate actual qos.
460*36371Ssklower 				 */
461*36371Ssklower 				if (((format & 0xc0) == 0) ||	/* high 2 bits zero ? */
462*36371Ssklower 					(((format & 0xc0) != CLNPOVAL_GLOBAL) &&
463*36371Ssklower 						((format & 0x3f) > 0))) /* not global,low bits used ? */
464*36371Ssklower 					return(GEN_HDRSYNTAX);
465*36371Ssklower 
466*36371Ssklower 				oidx->cni_qos_formatp = opts - (caddr_t)m;
467*36371Ssklower 				oidx->cni_qos_len = oplen;
468*36371Ssklower 
469*36371Ssklower 				opts += oplen;
470*36371Ssklower 			} break;
471*36371Ssklower 
472*36371Ssklower 			case CLNPOVAL_PRIOR: {
473*36371Ssklower 				if (prior++)				/* duplicate ? */
474*36371Ssklower 					return(GEN_DUPOPT);
475*36371Ssklower 				/*
476*36371Ssklower 				 *	priority: value must be one byte long
477*36371Ssklower 				 */
478*36371Ssklower 				if (oplen != 1)
479*36371Ssklower 					return(GEN_HDRSYNTAX);
480*36371Ssklower 
481*36371Ssklower 				oidx->cni_priorp = opts - (caddr_t)m;
482*36371Ssklower 
483*36371Ssklower 				opts += oplen;
484*36371Ssklower 			} break;
485*36371Ssklower 
486*36371Ssklower 			case CLNPOVAL_ERREAS: {
487*36371Ssklower 				/*
488*36371Ssklower 				 *	er reason: value must be two bytes long
489*36371Ssklower 				 */
490*36371Ssklower 				if (oplen != 2)
491*36371Ssklower 					return(GEN_HDRSYNTAX);
492*36371Ssklower 
493*36371Ssklower 				oidx->cni_er_reason = *opts;
494*36371Ssklower 
495*36371Ssklower 				opts += oplen;
496*36371Ssklower 			} break;
497*36371Ssklower 
498*36371Ssklower 			default: {
499*36371Ssklower 				IFDEBUG(D_OPTIONS)
500*36371Ssklower 					printf("clnp_opt_sanity: UNKNOWN OPTION 0x%x\n", opcode);
501*36371Ssklower 				ENDDEBUG
502*36371Ssklower 				return(DISC_UNSUPPOPT);
503*36371Ssklower 			}
504*36371Ssklower 		}
505*36371Ssklower 	}
506*36371Ssklower 		IFDEBUG(D_OPTIONS)
507*36371Ssklower 			printf("clnp_opt_sanity: return(0)\n", opcode);
508*36371Ssklower 		ENDDEBUG
509*36371Ssklower 	return(0);
510*36371Ssklower }
511*36371Ssklower #endif	ISO
512