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