adding GNU dc ("desk calculator")
[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 *
33 * @(#)clnp_input.c 7.13 (Berkeley) 5/6/91
34 */
35
36/***********************************************************
37 Copyright IBM Corporation 1987
38
39 All Rights Reserved
40
41Permission to use, copy, modify, and distribute this software and its
42documentation for any purpose and without fee is hereby granted,
43provided that the above copyright notice appear in all copies and that
44both that copyright notice and this permission notice appear in
45supporting documentation, and that the name of IBM not be
46used in advertising or publicity pertaining to distribution of the
47software without specific, written prior permission.
48
49IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
50ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
51IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
52ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
53WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
54ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55SOFTWARE.
56
57******************************************************************/
58
59/*
60 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 */
62/* $Header: /var/src/sys/netiso/RCS/clnp_input.c,v 5.1 89/02/09 16:20:32 hagens Exp $ */
63/* $Source: /var/src/sys/netiso/RCS/clnp_input.c,v $ */
64
65#include "types.h"
66#include "param.h"
67#include "mbuf.h"
68#include "domain.h"
69#include "protosw.h"
70#include "socket.h"
71#include "socketvar.h"
72#include "errno.h"
73#include "time.h"
74
75#include "../net/if.h"
76#include "../net/if_types.h"
77#include "../net/route.h"
78
79#include "iso.h"
80#include "iso_var.h"
81#include "iso_snpac.h"
82#include "clnp.h"
83#include "clnl.h"
84#include "esis.h"
85#include "../netinet/in_systm.h"
86#include "../netinet/ip.h"
87#include "../netinet/if_ether.h"
88#include "eonvar.h"
89#include "clnp_stat.h"
90#include "argo_debug.h"
91
92#ifdef ISO
93u_char clnp_protox[ISOPROTO_MAX];
94struct clnl_protosw clnl_protox[256];
95int clnpqmaxlen = IFQ_MAXLEN; /* RAH? why is this a variable */
96struct mbuf *clnp_data_ck();
97
98int clnp_input();
99
100int esis_input();
101
102#ifdef ISO_X25ESIS
103int x25esis_input();
104#endif ISO_X25ESIS
105
106/*
107 * FUNCTION: clnp_init
108 *
109 * PURPOSE: clnp initialization. Fill in clnp switch tables.
110 *
111 * RETURNS: none
112 *
113 * SIDE EFFECTS: fills in clnp_protox table with correct offsets into
114 * the isosw table.
115 *
116 * NOTES:
117 */
118clnp_init()
119{
120 register struct protosw *pr;
121
122 /*
123 * CLNP protox initialization
124 */
125 if ((pr = pffindproto(PF_ISO, ISOPROTO_RAW, SOCK_RAW)) == 0)
126 printf("clnl_init: no raw CLNP\n");
127 else
128 clnp_protox[ISOPROTO_RAW] = pr - isosw;
129
130 if ((pr = pffindproto(PF_ISO, ISOPROTO_TP, SOCK_SEQPACKET)) == 0)
131 printf("clnl_init: no tp/clnp\n");
132 else
133 clnp_protox[ISOPROTO_TP] = pr - isosw;
134
135 /*
136 * CLNL protox initialization
137 */
138 clnl_protox[ISO8473_CLNP].clnl_input = clnp_input;
139
140 clnlintrq.ifq_maxlen = clnpqmaxlen;
141}
142
143/*
144 * FUNCTION: clnlintr
145 *
146 * PURPOSE: Process a packet on the clnl input queue
147 *
148 * RETURNS: nothing.
149 *
150 * SIDE EFFECTS:
151 *
152 * NOTES:
153 */
154clnlintr()
155{
156 register struct mbuf *m; /* ptr to first mbuf of pkt */
157 register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */
158 int s; /* save and restore priority */
159 struct clnl_protosw *clnlsw;/* ptr to protocol switch */
160 struct snpa_hdr sh; /* subnetwork hdr */
161
162 /*
163 * Get next datagram off clnl input queue
164 */
165next:
166 s = splimp();
167 /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/
168 IF_DEQUEUE(&clnlintrq, m);
169 splx(s);
170
171
172 if (m == 0) /* nothing to do */
173 return;
174 if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) {
175 m_freem(m);
176 goto next;
177 } else {
178 register struct ifaddr *ifa;
179 for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next)
180 if (ifa->ifa_addr->sa_family == AF_ISO)
181 break;
182 if (ifa == 0) {
183 m_freem(m);
184 goto next;
185 }
186 }
187 bzero((caddr_t)&sh, sizeof(sh));
188 sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST);
189 switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) {
190 extern int ether_output();
191 case IFT_EON:
192 bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long));
193 bcopy(sizeof(u_long) + mtod(m, caddr_t),
194 (caddr_t)sh.snh_shost, sizeof(u_long));
195 sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) +
196 _offsetof(struct eon_hdr, eonh_class)];
197 m->m_data += EONIPLEN;
198 m->m_len -= EONIPLEN;
199 m->m_pkthdr.len -= EONIPLEN;
200 break;
201
202 default:
203 if (sh.snh_ifp->if_output == ether_output) {
204 bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost),
205 (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost));
206 m->m_data += sizeof (struct ether_header);
207 m->m_len -= sizeof (struct ether_header);
208 m->m_pkthdr.len -= sizeof (struct ether_header);
209 }
210 }
211 IFDEBUG(D_INPUT)
212 int i;
213 printf("clnlintr: src:");
214 for (i=0; i<6; i++)
215 printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
216 printf(" dst:");
217 for (i=0; i<6; i++)
218 printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
219 printf("\n");
220 ENDDEBUG
221
222 /*
223 * Get the fixed part of the clnl header into the first mbuf.
224 * Drop the packet if this fails.
225 * Do not call m_pullup if we have a cluster mbuf or the
226 * data is not there.
227 */
228 if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
229 ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
230 INCSTAT(cns_toosmall); /* TODO: use clnl stats */
231 goto next; /* m_pullup discards mbuf */
232 }
233
234 clnl = mtod(m, struct clnl_fixed *);
235
236 /*
237 * Drop packet if the length of the header is not reasonable.
238 */
239 if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
240 (clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
241 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
242 m_freem(m);
243 goto next;
244 }
245
246 /*
247 * If the header is not contained in this mbuf, make it so.
248 * Drop packet if this fails.
249 * Note: m_pullup will allocate a cluster mbuf if necessary
250 */
251 if (clnl->cnf_hdr_len > m->m_len) {
252 if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) {
253 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
254 goto next; /* m_pullup discards mbuf */
255 }
256 clnl = mtod(m, struct clnl_fixed *);
257 }
258
259 clnlsw = &clnl_protox[clnl->cnf_proto_id];
260
261
262 if (clnlsw->clnl_input)
263 (*clnlsw->clnl_input) (m, &sh);
264 else
265 m_freem(m);
266
267 goto next;
268}
269
270/*
271 * FUNCTION: clnp_input
272 *
273 * PURPOSE: process an incoming clnp packet
274 *
275 * RETURNS: nothing
276 *
277 * SIDE EFFECTS: increments fields of clnp_stat structure.
278 *
279 * NOTES:
280 * TODO: I would like to make seg_part a pointer into the mbuf, but
281 * will it be correctly aligned?
282 */
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}
564#endif ISO