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