xref: /original-bsd/sys/netiso/clnp_input.c (revision a5a0fb88)
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: clnp_input.c,v 4.4 88/09/08 08:38:15 hagens Exp $ */
28 /* $Source: /usr/argo/sys/netiso/RCS/clnp_input.c,v $ */
29 
30 #ifndef lint
31 static char *rcsid = "$Header: clnp_input.c,v 4.4 88/09/08 08:38:15 hagens Exp $";
32 #endif lint
33 
34 #include "../h/types.h"
35 #include "../h/param.h"
36 #include "../h/mbuf.h"
37 #include "../h/domain.h"
38 #include "../h/protosw.h"
39 #include "../h/socket.h"
40 #include "../h/socketvar.h"
41 #include "../h/errno.h"
42 #include "../h/time.h"
43 
44 #include "../net/if.h"
45 #include "../net/route.h"
46 
47 #include "../netiso/iso.h"
48 #include "../netiso/iso_var.h"
49 #include "../netiso/iso_snpac.h"
50 #include "../netiso/clnp.h"
51 #include "../netiso/clnl.h"
52 #include "../netiso/esis.h"
53 #include "../netiso/clnp_stat.h"
54 #include "../netiso/argo_debug.h"
55 
56 #ifdef ISO
57 u_char		clnp_protox[ISOPROTO_MAX];
58 struct clnl_protosw clnl_protox[256];
59 int			clnpqmaxlen = IFQ_MAXLEN;	/* RAH? why is this a variable */
60 struct mbuf	*clnp_data_ck();
61 
62 int	clnp_input();
63 
64 int	esis_input();
65 
66 #ifdef	ISO_X25ESIS
67 int	x25esis_input();
68 #endif	ISO_X25ESIS
69 
70 /*
71  * FUNCTION:		clnp_init
72  *
73  * PURPOSE:			clnp initialization. Fill in clnp switch tables.
74  *
75  * RETURNS:			none
76  *
77  * SIDE EFFECTS:	fills in clnp_protox table with correct offsets into
78  *					the isosw table.
79  *
80  * NOTES:
81  */
82 clnp_init()
83 {
84 	register struct protosw *pr;
85 
86 	/*
87 	 *	CLNP protox initialization
88 	 */
89 	if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0)
90 		printf("clnl_init: no raw CLNP\n");
91 	else
92 		clnp_protox[ISOPROTO_RAW] = pr - isosw;
93 
94 	if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0)
95 		printf("clnl_init: no tp/clnp\n");
96 	else
97 		clnp_protox[ISOPROTO_TP] = pr - isosw;
98 
99 	/*
100 	 *	CLNL protox initialization
101 	 */
102 	clnl_protox[ISO8473_CLNP].clnl_input = clnp_input;
103 
104 	clnlintrq.ifq_maxlen = clnpqmaxlen;
105 }
106 
107 /*
108  * FUNCTION:		clnlintr
109  *
110  * PURPOSE:			Process a packet on the clnl input queue
111  *
112  * RETURNS:			nothing.
113  *
114  * SIDE EFFECTS:
115  *
116  * NOTES:
117  */
118 clnlintr()
119 {
120 	register struct mbuf		*m;		/* ptr to first mbuf of pkt */
121 	register struct clnl_fixed	*clnl;	/* ptr to fixed part of clnl hdr */
122 	struct ifnet				*ifp;	/* ptr to interface pkt arrived on */
123 	int							s;		/* save and restore priority */
124 	struct clnl_protosw			*clnlsw;/* ptr to protocol switch */
125 	struct snpa_hdr				sh;		/* subnetwork hdr */
126 
127 	/*
128 	 *	Get next datagram off clnl input queue
129 	 */
130 next:
131 	s = splimp();
132 
133 	IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);
134 
135 	IFDEBUG(D_INPUT)
136 		int i;
137 		printf("clnlintr: src:");
138 		for (i=0; i<6; i++)
139 			printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
140 		printf(" dst:");
141 		for (i=0; i<6; i++)
142 			printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
143 		printf("\n");
144 	ENDDEBUG
145 
146 	splx(s);
147 	if (m == 0)		/* nothing to do */
148 		return;
149 
150 	/*
151 	 *	Get the fixed part of the clnl header into the first mbuf.
152 	 *	Drop the packet if this fails.
153 	 *	Do not call m_pullup if we have a cluster mbuf or the
154 	 *	data is not there.
155 	 */
156 	if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
157 		((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
158 		INCSTAT(cns_toosmall);	/* TODO: use clnl stats */
159 		goto next;				/* m_pullup discards mbuf */
160 	}
161 
162 	clnl = mtod(m, struct clnl_fixed *);
163 
164 	/*
165 	 *	Drop packet if the length of the header is not reasonable.
166 	 */
167 	if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
168 		(clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
169 		INCSTAT(cns_badhlen);	/* TODO: use clnl stats */
170 		m_freem(m);
171 		goto next;
172 	}
173 
174 	/*
175 	 *	If the header is not contained in this mbuf, make it so.
176 	 *	Drop packet if this fails.
177 	 *	Note: m_pullup will allocate a cluster mbuf if necessary
178 	 */
179 	if (clnl->cnf_hdr_len > m->m_len) {
180 		if ((m = m_pullup(m, clnl->cnf_hdr_len)) == 0) {
181 			INCSTAT(cns_badhlen);	/* TODO: use clnl stats */
182 			goto next;	/* m_pullup discards mbuf */
183 		}
184 		clnl = mtod(m, struct clnl_fixed *);
185 	}
186 
187 	clnlsw = &clnl_protox[clnl->cnf_proto_id];
188 
189 
190 	if (clnlsw->clnl_input)
191 		(*clnlsw->clnl_input) (m, &sh);
192 	else
193 		m_freem(m);
194 
195 	goto next;
196 }
197 
198 /*
199  * FUNCTION:		clnp_input
200  *
201  * PURPOSE:			process an incoming clnp packet
202  *
203  * RETURNS:			nothing
204  *
205  * SIDE EFFECTS:	increments fields of clnp_stat structure.
206  *
207  * NOTES:
208  *	TODO: I would like to make seg_part a pointer into the mbuf, but
209  *	will it be correctly aligned?
210  */
211 int clnp_input(m, shp)
212 struct mbuf		*m;		/* ptr to first mbuf of pkt */
213 struct snpa_hdr	*shp;	/* subnetwork header */
214 {
215 	register struct clnp_fixed	*clnp;	/* ptr to fixed part of header */
216 	struct iso_addr				src;	/* source address of pkt */
217 	struct iso_addr				dst;	/* destination address of pkt */
218 	caddr_t						hoff;	/* current offset in packet */
219 	caddr_t						hend;	/* address of end of header info */
220 	struct clnp_segment			seg_part; /* segment part of hdr */
221 	int							seg_off=0; /* offset of segment part of hdr */
222 	int							seg_len;/* length of packet data&hdr in bytes */
223 	struct clnp_optidx			oidx, *oidxp = NULL;	/* option index */
224 	extern int 					iso_systype;	/* used by ESIS config resp */
225 
226 	IFDEBUG(D_INPUT)
227 		printf(
228 		"clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, data:\n",
229 			m->m_len, m->m_type);
230 	ENDDEBUG
231 	IFDEBUG(D_DUMPIN)
232 		printf("clnp_input: first mbuf:\n");
233 		dump_buf(mtod(m, caddr_t), m->m_len);
234 	ENDDEBUG
235 
236 	/*
237 	 *	If no iso addresses have been set, there is nothing
238 	 *	to do with the packet.
239 	 */
240 	if (iso_ifaddr == NULL) {
241 		clnp_discard(m, ADDR_DESTUNREACH);
242 		return;
243 	}
244 
245 	INCSTAT(cns_total);
246 	clnp = mtod(m, struct clnp_fixed *);
247 
248 	/*
249 	 *	Compute checksum (if necessary) and drop packet if
250 	 *	checksum does not match
251 	 */
252 	if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, clnp->cnf_hdr_len)) {
253 		INCSTAT(cns_badcsum);
254 		clnp_discard(m, GEN_BADCSUM);
255 		return;
256 	}
257 
258 	if (clnp->cnf_vers != ISO8473_V1) {
259 		INCSTAT(cns_badvers);
260 		clnp_discard(m, DISC_UNSUPPVERS);
261 		return;
262 	}
263 
264 
265  	/* check mbuf data length: clnp_data_ck will free mbuf upon error */
266 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
267 	if ((m = clnp_data_ck(m, seg_len)) == 0)
268 		return;
269 
270 	clnp = mtod(m, struct clnp_fixed *);
271 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
272 
273 	/*
274 	 *	extract the source and destination address
275 	 *	drop packet on failure
276 	 */
277 	bzero((caddr_t)&src, sizeof(src));
278 	bzero((caddr_t)&dst, sizeof(dst));
279 
280 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
281 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
282 	if (hoff == (caddr_t)0) {
283 		INCSTAT(cns_badaddr);
284 		clnp_discard(m, GEN_INCOMPLETE);
285 		return;
286 	}
287 	CLNP_EXTRACT_ADDR(src, hoff, hend);
288 	if (hoff == (caddr_t)0) {
289 		INCSTAT(cns_badaddr);
290 		clnp_discard(m, GEN_INCOMPLETE);
291 		return;
292 	}
293 
294 	IFDEBUG(D_INPUT)
295 		printf("clnp_input: from %s", clnp_iso_addrp(&src));
296 		printf(" to %s\n", clnp_iso_addrp(&dst));
297 	ENDDEBUG
298 
299 	/*
300 	 *	extract the segmentation information, if it is present.
301 	 *	drop packet on failure
302 	 */
303 	if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok)) {
304 		if (hoff + sizeof(struct clnp_segment) > hend) {
305 			INCSTAT(cns_noseg);
306 			clnp_discard(m, GEN_INCOMPLETE);
307 			return;
308 		} else {
309 			(void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
310 			/* make sure segmentation fields are in host order */
311 			seg_part.cng_id = ntohs(seg_part.cng_id);
312 			seg_part.cng_off = ntohs(seg_part.cng_off);
313 			seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
314 			seg_off = hoff - (caddr_t)clnp;
315 			hoff += sizeof(struct clnp_segment);
316 		}
317 	}
318 
319 	/*
320 	 *	process options if present. If clnp_opt_sanity returns
321 	 *	false (indicating an error was found in the options) or
322 	 *	an unsupported option was found
323 	 *	then drop packet and emit an ER.
324 	 */
325 	if (hoff < hend) {
326 		int		errcode;
327 
328 		oidxp = &oidx;
329 		errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
330 
331 		/* we do not support security */
332 		if ((errcode == 0) && (oidxp->cni_securep))
333 			errcode = DISC_UNSUPPSECURE;
334 
335 		/* the er option is valid with ER pdus only */
336 		if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
337 			(clnp->cnf_type != CLNP_ER))
338 			errcode = DISC_UNSUPPOPT;
339 
340 		if (errcode != 0) {
341 			clnp_discard(m, (char)errcode);
342 			IFDEBUG(D_INPUT)
343 				printf("clnp_input: dropped (err x%x) due to bad options\n",
344 					errcode);
345 			ENDDEBUG
346 			return;
347 		}
348 	}
349 
350 	/*
351 	 *	check if this packet is for us. if not, then forward
352 	 */
353 	if (clnp_ours(&dst) == 0) {
354 		IFDEBUG(D_INPUT)
355 			printf("clnp_input: forwarding packet not for us\n");
356 		ENDDEBUG
357  		clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
358 		return;
359 	}
360 
361 	/*
362 	 *	ESIS Configuration Response Function
363 	 *
364 	 *	If the packet received was sent to the multicast address
365 	 *	all end systems, then send an esh to the source
366 	 */
367 	if ((IS_MULTICAST(shp->snh_dhost)) && (iso_systype == SNPA_ES)) {
368 		extern short esis_holding_time;
369 
370 		esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
371 			shp->snh_shost, 6);
372 	}
373 
374 	/*
375 	 *	If this is a fragment, then try to reassemble it. If clnp_reass
376 	 *	returns non NULL, the packet has been reassembled, and should
377 	 *	be give to TP. Otherwise the fragment has been delt with
378 	 *	by the reassembly code (either stored or deleted). In either case
379 	 *	we should have nothing more to do with it.
380 	 */
381 	if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok) &&
382 		(seg_len != seg_part.cng_tot_len)) {
383 		struct mbuf	*m0;
384 
385 		if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
386 			m = m0;
387 			clnp = mtod(m, struct clnp_fixed *);
388 		} else {
389 			return;
390 		}
391 	}
392 
393 	/*
394 	 *	give the packet to the higher layer
395 	 *	TODO: how do we tell TP that congestion bit is on in QOS option?
396 	 *
397 	 *	Note: the total length of packet
398 	 *	is the total length field of the segmentation part,
399 	 *	or, if absent, the segment length field of the
400 	 *	header.
401 	 */
402 	switch (clnp->cnf_type) {
403 	case CLNP_ER:
404 		/*
405 		 *	This ER must have the er option.
406 		 *	If the option is not present, discard datagram.
407 		 */
408 		if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
409 			clnp_discard(m, GEN_HDRSYNTAX);
410 		} else {
411 			clnp_er_input(m, &src, oidxp->cni_er_reason);
412 		}
413 		break;
414 
415 	case CLNP_DT:
416 		(*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &src, &dst,
417 			clnp->cnf_hdr_len);
418 		break;
419 
420  	case CLNP_RAW:
421 	case CLNP_ECR:
422 		IFDEBUG(D_INPUT)
423 			printf("clnp_input: raw input of %d bytes\n",
424 				clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len);
425 		ENDDEBUG
426 		(*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &src, &dst,
427 					clnp->cnf_hdr_len);
428 		break;
429 
430 	case CLNP_EC:
431 		IFDEBUG(D_INPUT)
432 			printf("clnp_input: echoing packet\n");
433 		ENDDEBUG
434 		/*
435 		 *	Switch the source and destination address,
436 		 */
437 		hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
438 		CLNP_INSERT_ADDR(hoff, &src);
439 		CLNP_INSERT_ADDR(hoff, &dst);
440 		clnp->cnf_type = CLNP_ECR;
441 
442 		/*
443 		 *	Forward back to sender
444 		 */
445  		clnp_forward(m, clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len,
446 			&src, oidxp, seg_off, shp);
447 		break;
448 
449 	default:
450  		printf("clnp_input: unknown clnp pkt type %d\n", clnp->cnf_type);
451 		clnp_discard(m, GEN_HDRSYNTAX);
452  		break;
453 	}
454 }
455 
456 int clnp_ctlinput()
457 {
458 }
459 
460 #endif ISO
461