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