xref: /csrg-svn/sys/netiso/clnp_input.c (revision 36765)
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 /*	@(#)clnp_input.c	7.2 (Berkeley) 02/14/89 */
30 
31 #ifndef lint
32 static char *rcsid = "$Header: clnp_input.c,v 4.4 88/09/08 08:38:15 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 
238 	IFDEBUG(D_INPUT)
239 		printf(
240 		"clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, data:\n",
241 			m->m_len, m->m_type);
242 	ENDDEBUG
243 	IFDEBUG(D_DUMPIN)
244 		printf("clnp_input: first mbuf:\n");
245 		dump_buf(mtod(m, caddr_t), m->m_len);
246 	ENDDEBUG
247 
248 	/*
249 	 *	If no iso addresses have been set, there is nothing
250 	 *	to do with the packet.
251 	 */
252 	if (iso_ifaddr == NULL) {
253 		clnp_discard(m, ADDR_DESTUNREACH);
254 		return;
255 	}
256 
257 	INCSTAT(cns_total);
258 	clnp = mtod(m, struct clnp_fixed *);
259 
260 	/*
261 	 *	Compute checksum (if necessary) and drop packet if
262 	 *	checksum does not match
263 	 */
264 	if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, clnp->cnf_hdr_len)) {
265 		INCSTAT(cns_badcsum);
266 		clnp_discard(m, GEN_BADCSUM);
267 		return;
268 	}
269 
270 	if (clnp->cnf_vers != ISO8473_V1) {
271 		INCSTAT(cns_badvers);
272 		clnp_discard(m, DISC_UNSUPPVERS);
273 		return;
274 	}
275 
276 
277  	/* check mbuf data length: clnp_data_ck will free mbuf upon error */
278 	CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
279 	if ((m = clnp_data_ck(m, seg_len)) == 0)
280 		return;
281 
282 	clnp = mtod(m, struct clnp_fixed *);
283 	hend = (caddr_t)clnp + clnp->cnf_hdr_len;
284 
285 	/*
286 	 *	extract the source and destination address
287 	 *	drop packet on failure
288 	 */
289 	bzero((caddr_t)&src, sizeof(src));
290 	bzero((caddr_t)&dst, sizeof(dst));
291 
292 	hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
293 	CLNP_EXTRACT_ADDR(dst, hoff, hend);
294 	if (hoff == (caddr_t)0) {
295 		INCSTAT(cns_badaddr);
296 		clnp_discard(m, GEN_INCOMPLETE);
297 		return;
298 	}
299 	CLNP_EXTRACT_ADDR(src, hoff, hend);
300 	if (hoff == (caddr_t)0) {
301 		INCSTAT(cns_badaddr);
302 		clnp_discard(m, GEN_INCOMPLETE);
303 		return;
304 	}
305 
306 	IFDEBUG(D_INPUT)
307 		printf("clnp_input: from %s", clnp_iso_addrp(&src));
308 		printf(" to %s\n", clnp_iso_addrp(&dst));
309 	ENDDEBUG
310 
311 	/*
312 	 *	extract the segmentation information, if it is present.
313 	 *	drop packet on failure
314 	 */
315 	if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok)) {
316 		if (hoff + sizeof(struct clnp_segment) > hend) {
317 			INCSTAT(cns_noseg);
318 			clnp_discard(m, GEN_INCOMPLETE);
319 			return;
320 		} else {
321 			(void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
322 			/* make sure segmentation fields are in host order */
323 			seg_part.cng_id = ntohs(seg_part.cng_id);
324 			seg_part.cng_off = ntohs(seg_part.cng_off);
325 			seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
326 			seg_off = hoff - (caddr_t)clnp;
327 			hoff += sizeof(struct clnp_segment);
328 		}
329 	}
330 
331 	/*
332 	 *	process options if present. If clnp_opt_sanity returns
333 	 *	false (indicating an error was found in the options) or
334 	 *	an unsupported option was found
335 	 *	then drop packet and emit an ER.
336 	 */
337 	if (hoff < hend) {
338 		int		errcode;
339 
340 		oidxp = &oidx;
341 		errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
342 
343 		/* we do not support security */
344 		if ((errcode == 0) && (oidxp->cni_securep))
345 			errcode = DISC_UNSUPPSECURE;
346 
347 		/* the er option is valid with ER pdus only */
348 		if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
349 			(clnp->cnf_type != CLNP_ER))
350 			errcode = DISC_UNSUPPOPT;
351 
352 		if (errcode != 0) {
353 			clnp_discard(m, (char)errcode);
354 			IFDEBUG(D_INPUT)
355 				printf("clnp_input: dropped (err x%x) due to bad options\n",
356 					errcode);
357 			ENDDEBUG
358 			return;
359 		}
360 	}
361 
362 	/*
363 	 *	check if this packet is for us. if not, then forward
364 	 */
365 	if (clnp_ours(&dst) == 0) {
366 		IFDEBUG(D_INPUT)
367 			printf("clnp_input: forwarding packet not for us\n");
368 		ENDDEBUG
369  		clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
370 		return;
371 	}
372 
373 	/*
374 	 *	ESIS Configuration Response Function
375 	 *
376 	 *	If the packet received was sent to the multicast address
377 	 *	all end systems, then send an esh to the source
378 	 */
379 	if ((IS_MULTICAST(shp->snh_dhost)) && (iso_systype == SNPA_ES)) {
380 		extern short esis_holding_time;
381 
382 		esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
383 			shp->snh_shost, 6);
384 	}
385 
386 	/*
387 	 *	If this is a fragment, then try to reassemble it. If clnp_reass
388 	 *	returns non NULL, the packet has been reassembled, and should
389 	 *	be give to TP. Otherwise the fragment has been delt with
390 	 *	by the reassembly code (either stored or deleted). In either case
391 	 *	we should have nothing more to do with it.
392 	 */
393 	if ((clnp->cnf_type != CLNP_ER) && (clnp->cnf_seg_ok) &&
394 		(seg_len != seg_part.cng_tot_len)) {
395 		struct mbuf	*m0;
396 
397 		if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
398 			m = m0;
399 			clnp = mtod(m, struct clnp_fixed *);
400 		} else {
401 			return;
402 		}
403 	}
404 
405 	/*
406 	 *	give the packet to the higher layer
407 	 *	TODO: how do we tell TP that congestion bit is on in QOS option?
408 	 *
409 	 *	Note: the total length of packet
410 	 *	is the total length field of the segmentation part,
411 	 *	or, if absent, the segment length field of the
412 	 *	header.
413 	 */
414 	switch (clnp->cnf_type) {
415 	case CLNP_ER:
416 		/*
417 		 *	This ER must have the er option.
418 		 *	If the option is not present, discard datagram.
419 		 */
420 		if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
421 			clnp_discard(m, GEN_HDRSYNTAX);
422 		} else {
423 			clnp_er_input(m, &src, oidxp->cni_er_reason);
424 		}
425 		break;
426 
427 	case CLNP_DT:
428 		(*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &src, &dst,
429 			clnp->cnf_hdr_len);
430 		break;
431 
432  	case CLNP_RAW:
433 	case CLNP_ECR:
434 		IFDEBUG(D_INPUT)
435 			printf("clnp_input: raw input of %d bytes\n",
436 				clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len);
437 		ENDDEBUG
438 		(*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &src, &dst,
439 					clnp->cnf_hdr_len);
440 		break;
441 
442 	case CLNP_EC:
443 		IFDEBUG(D_INPUT)
444 			printf("clnp_input: echoing packet\n");
445 		ENDDEBUG
446 		/*
447 		 *	Switch the source and destination address,
448 		 */
449 		hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
450 		CLNP_INSERT_ADDR(hoff, &src);
451 		CLNP_INSERT_ADDR(hoff, &dst);
452 		clnp->cnf_type = CLNP_ECR;
453 
454 		/*
455 		 *	Forward back to sender
456 		 */
457  		clnp_forward(m, clnp->cnf_seg_ok ? seg_part.cng_tot_len : seg_len,
458 			&src, oidxp, seg_off, shp);
459 		break;
460 
461 	default:
462  		printf("clnp_input: unknown clnp pkt type %d\n", clnp->cnf_type);
463 		clnp_discard(m, GEN_HDRSYNTAX);
464  		break;
465 	}
466 }
467 
468 int clnp_ctlinput()
469 {
470 }
471 
472 #endif ISO
473