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