Media table reorganization.
[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
4c45483e 34 * $Id: clnp_input.c,v 1.2 1993/10/16 21:04:48 rgrimes 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
RG
63
64#include "types.h"
65#include "param.h"
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
RG
98
99int esis_input();
100
101#ifdef ISO_X25ESIS
102int x25esis_input();
103#endif ISO_X25ESIS
104
105/*
106 * FUNCTION: clnp_init
107 *
108 * PURPOSE: clnp initialization. Fill in clnp switch tables.
109 *
110 * RETURNS: none
111 *
112 * SIDE EFFECTS: fills in clnp_protox table with correct offsets into
113 * the isosw table.
114 *
115 * NOTES:
116 */
4c45483e 117void
15637ed4
RG
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 */
4c45483e 154void
15637ed4
RG
155clnlintr()
156{
157 register struct mbuf *m; /* ptr to first mbuf of pkt */
158 register struct clnl_fixed *clnl; /* ptr to fixed part of clnl hdr */
159 int s; /* save and restore priority */
160 struct clnl_protosw *clnlsw;/* ptr to protocol switch */
161 struct snpa_hdr sh; /* subnetwork hdr */
162
163 /*
164 * Get next datagram off clnl input queue
165 */
166next:
167 s = splimp();
168 /* IF_DEQUEUESNPAHDR(&clnlintrq, m, sh);*/
169 IF_DEQUEUE(&clnlintrq, m);
170 splx(s);
171
172
173 if (m == 0) /* nothing to do */
174 return;
175 if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.rcvif == 0) {
176 m_freem(m);
177 goto next;
178 } else {
179 register struct ifaddr *ifa;
180 for (ifa = m->m_pkthdr.rcvif->if_addrlist; ifa; ifa = ifa->ifa_next)
181 if (ifa->ifa_addr->sa_family == AF_ISO)
182 break;
183 if (ifa == 0) {
184 m_freem(m);
185 goto next;
186 }
187 }
188 bzero((caddr_t)&sh, sizeof(sh));
189 sh.snh_flags = m->m_flags & (M_MCAST|M_BCAST);
190 switch((sh.snh_ifp = m->m_pkthdr.rcvif)->if_type) {
191 extern int ether_output();
192 case IFT_EON:
193 bcopy(mtod(m, caddr_t), (caddr_t)sh.snh_dhost, sizeof(u_long));
194 bcopy(sizeof(u_long) + mtod(m, caddr_t),
195 (caddr_t)sh.snh_shost, sizeof(u_long));
196 sh.snh_dhost[4] = mtod(m, u_char *)[sizeof(struct ip) +
197 _offsetof(struct eon_hdr, eonh_class)];
198 m->m_data += EONIPLEN;
199 m->m_len -= EONIPLEN;
200 m->m_pkthdr.len -= EONIPLEN;
201 break;
202
203 default:
204 if (sh.snh_ifp->if_output == ether_output) {
205 bcopy((caddr_t)(mtod(m, struct ether_header *)->ether_dhost),
206 (caddr_t)sh.snh_dhost, 2*sizeof(sh.snh_dhost));
207 m->m_data += sizeof (struct ether_header);
208 m->m_len -= sizeof (struct ether_header);
209 m->m_pkthdr.len -= sizeof (struct ether_header);
210 }
211 }
212 IFDEBUG(D_INPUT)
213 int i;
214 printf("clnlintr: src:");
215 for (i=0; i<6; i++)
216 printf("%x%c", sh.snh_shost[i] & 0xff, (i<5) ? ':' : ' ');
217 printf(" dst:");
218 for (i=0; i<6; i++)
219 printf("%x%c", sh.snh_dhost[i] & 0xff, (i<5) ? ':' : ' ');
220 printf("\n");
221 ENDDEBUG
222
223 /*
224 * Get the fixed part of the clnl header into the first mbuf.
225 * Drop the packet if this fails.
226 * Do not call m_pullup if we have a cluster mbuf or the
227 * data is not there.
228 */
229 if ((IS_CLUSTER(m) || (m->m_len < sizeof(struct clnl_fixed))) &&
230 ((m = m_pullup(m, sizeof(struct clnl_fixed))) == 0)) {
231 INCSTAT(cns_toosmall); /* TODO: use clnl stats */
232 goto next; /* m_pullup discards mbuf */
233 }
234
235 clnl = mtod(m, struct clnl_fixed *);
236
237 /*
238 * Drop packet if the length of the header is not reasonable.
239 */
240 if ((clnl->cnf_hdr_len < CLNP_HDR_MIN) ||
241 (clnl->cnf_hdr_len > CLNP_HDR_MAX)) {
242 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
243 m_freem(m);
244 goto next;
245 }
246
247 /*
248 * If the header is not contained in this mbuf, make it so.
249 * Drop packet if this fails.
250 * Note: m_pullup will allocate a cluster mbuf if necessary
251 */
252 if (clnl->cnf_hdr_len > m->m_len) {
253 if ((m = m_pullup(m, (int)clnl->cnf_hdr_len)) == 0) {
254 INCSTAT(cns_badhlen); /* TODO: use clnl stats */
255 goto next; /* m_pullup discards mbuf */
256 }
257 clnl = mtod(m, struct clnl_fixed *);
258 }
259
260 clnlsw = &clnl_protox[clnl->cnf_proto_id];
261
262
263 if (clnlsw->clnl_input)
264 (*clnlsw->clnl_input) (m, &sh);
265 else
266 m_freem(m);
267
268 goto next;
269}
270
271/*
272 * FUNCTION: clnp_input
273 *
274 * PURPOSE: process an incoming clnp packet
275 *
276 * RETURNS: nothing
277 *
278 * SIDE EFFECTS: increments fields of clnp_stat structure.
279 *
280 * NOTES:
281 * TODO: I would like to make seg_part a pointer into the mbuf, but
282 * will it be correctly aligned?
283 */
4c45483e 284void
15637ed4
RG
285clnp_input(m, shp)
286struct mbuf *m; /* ptr to first mbuf of pkt */
287struct snpa_hdr *shp; /* subnetwork header */
288{
289 register struct clnp_fixed *clnp; /* ptr to fixed part of header */
290 struct sockaddr_iso source; /* source address of pkt */
291 struct sockaddr_iso target; /* destination address of pkt */
292#define src source.siso_addr
293#define dst target.siso_addr
294 caddr_t hoff; /* current offset in packet */
295 caddr_t hend; /* address of end of header info */
296 struct clnp_segment seg_part; /* segment part of hdr */
297 int seg_off=0; /* offset of segment part of hdr */
298 int seg_len;/* length of packet data&hdr in bytes */
299 struct clnp_optidx oidx, *oidxp = NULL; /* option index */
300 extern int iso_systype; /* used by ESIS config resp */
301 extern struct sockaddr_iso blank_siso; /* used for initializing */
302 int need_afrin = 0;
303 /* true if congestion experienced */
304 /* which means you need afrin nose */
305 /* spray. How clever! */
306
307 IFDEBUG(D_INPUT)
308 printf(
309 "clnp_input: proccessing dg; First mbuf m_len %d, m_type x%x, %s\n",
310 m->m_len, m->m_type, IS_CLUSTER(m) ? "cluster" : "normal");
311 ENDDEBUG
312 need_afrin = 0;
313
314 /*
315 * If no iso addresses have been set, there is nothing
316 * to do with the packet.
317 */
318 if (iso_ifaddr == NULL) {
319 clnp_discard(m, ADDR_DESTUNREACH);
320 return;
321 }
322
323 INCSTAT(cns_total);
324 clnp = mtod(m, struct clnp_fixed *);
325
326 IFDEBUG(D_DUMPIN)
327 struct mbuf *mhead;
328 int total_len = 0;
329 printf("clnp_input: clnp header:\n");
330 dump_buf(mtod(m, caddr_t), clnp->cnf_hdr_len);
331 printf("clnp_input: mbuf chain:\n");
332 for (mhead = m; mhead != NULL; mhead=mhead->m_next) {
333 printf("m x%x, len %d\n", mhead, mhead->m_len);
334 total_len += mhead->m_len;
335 }
336 printf("clnp_input: total length of mbuf chain %d:\n", total_len);
337 ENDDEBUG
338
339 /*
340 * Compute checksum (if necessary) and drop packet if
341 * checksum does not match
342 */
343 if (CKSUM_REQUIRED(clnp) && iso_check_csum(m, (int)clnp->cnf_hdr_len)) {
344 INCSTAT(cns_badcsum);
345 clnp_discard(m, GEN_BADCSUM);
346 return;
347 }
348
349 if (clnp->cnf_vers != ISO8473_V1) {
350 INCSTAT(cns_badvers);
351 clnp_discard(m, DISC_UNSUPPVERS);
352 return;
353 }
354
355
356 /* check mbuf data length: clnp_data_ck will free mbuf upon error */
357 CTOH(clnp->cnf_seglen_msb, clnp->cnf_seglen_lsb, seg_len);
358 if ((m = clnp_data_ck(m, seg_len)) == 0)
359 return;
360
361 clnp = mtod(m, struct clnp_fixed *);
362 hend = (caddr_t)clnp + clnp->cnf_hdr_len;
363
364 /*
365 * extract the source and destination address
366 * drop packet on failure
367 */
368 source = target = blank_siso;
369
370 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
371 CLNP_EXTRACT_ADDR(dst, hoff, hend);
372 if (hoff == (caddr_t)0) {
373 INCSTAT(cns_badaddr);
374 clnp_discard(m, GEN_INCOMPLETE);
375 return;
376 }
377 CLNP_EXTRACT_ADDR(src, hoff, hend);
378 if (hoff == (caddr_t)0) {
379 INCSTAT(cns_badaddr);
380 clnp_discard(m, GEN_INCOMPLETE);
381 return;
382 }
383
384 IFDEBUG(D_INPUT)
385 printf("clnp_input: from %s", clnp_iso_addrp(&src));
386 printf(" to %s\n", clnp_iso_addrp(&dst));
387 ENDDEBUG
388
389 /*
390 * extract the segmentation information, if it is present.
391 * drop packet on failure
392 */
393 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
394 (clnp->cnf_type & CNF_SEG_OK)) {
395 if (hoff + sizeof(struct clnp_segment) > hend) {
396 INCSTAT(cns_noseg);
397 clnp_discard(m, GEN_INCOMPLETE);
398 return;
399 } else {
400 (void) bcopy(hoff, (caddr_t)&seg_part, sizeof(struct clnp_segment));
401 /* make sure segmentation fields are in host order */
402 seg_part.cng_id = ntohs(seg_part.cng_id);
403 seg_part.cng_off = ntohs(seg_part.cng_off);
404 seg_part.cng_tot_len = ntohs(seg_part.cng_tot_len);
405 seg_off = hoff - (caddr_t)clnp;
406 hoff += sizeof(struct clnp_segment);
407 }
408 }
409
410 /*
411 * process options if present. If clnp_opt_sanity returns
412 * false (indicating an error was found in the options) or
413 * an unsupported option was found
414 * then drop packet and emit an ER.
415 */
416 if (hoff < hend) {
417 int errcode;
418
419 oidxp = &oidx;
420 errcode = clnp_opt_sanity(m, hoff, hend-hoff, oidxp);
421
422 /* we do not support security */
423 if ((errcode == 0) && (oidxp->cni_securep))
424 errcode = DISC_UNSUPPSECURE;
425
426 /* the er option is valid with ER pdus only */
427 if ((errcode == 0) && (oidxp->cni_er_reason != ER_INVALREAS) &&
428 ((clnp->cnf_type & CNF_TYPE) != CLNP_ER))
429 errcode = DISC_UNSUPPOPT;
430
431#ifdef DECBIT
432 /* check if the congestion experienced bit is set */
433 if (oidxp->cni_qos_formatp) {
434 caddr_t qosp = CLNP_OFFTOOPT(m, oidxp->cni_qos_formatp);
435 u_char qos = *qosp;
436
437 need_afrin = ((qos & (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED)) ==
438 (CLNPOVAL_GLOBAL|CLNPOVAL_CONGESTED));
439 if (need_afrin)
440 INCSTAT(cns_congest_rcvd);
441 }
442#endif DECBIT
443
444 if (errcode != 0) {
445 clnp_discard(m, (char)errcode);
446 IFDEBUG(D_INPUT)
447 printf("clnp_input: dropped (err x%x) due to bad options\n",
448 errcode);
449 ENDDEBUG
450 return;
451 }
452 }
453
454 /*
455 * check if this packet is for us. if not, then forward
456 */
457 if (clnp_ours(&dst) == 0) {
458 IFDEBUG(D_INPUT)
459 printf("clnp_input: forwarding packet not for us\n");
460 ENDDEBUG
461 clnp_forward(m, seg_len, &dst, oidxp, seg_off, shp);
462 return;
463 }
464
465 /*
466 * ESIS Configuration Response Function
467 *
468 * If the packet received was sent to the multicast address
469 * all end systems, then send an esh to the source
470 */
471 if ((shp->snh_flags & M_MCAST) && (iso_systype == SNPA_ES)) {
472 extern short esis_holding_time;
473
474 esis_shoutput(shp->snh_ifp, ESIS_ESH, esis_holding_time,
475 shp->snh_shost, 6, &dst);
476 }
477
478 /*
479 * If this is a fragment, then try to reassemble it. If clnp_reass
480 * returns non NULL, the packet has been reassembled, and should
481 * be give to TP. Otherwise the fragment has been delt with
482 * by the reassembly code (either stored or deleted). In either case
483 * we should have nothing more to do with it.
484 */
485 if (((clnp->cnf_type & CNF_TYPE) != CLNP_ER) &&
486 (clnp->cnf_type & CNF_SEG_OK) &&
487 (seg_len != seg_part.cng_tot_len)) {
488 struct mbuf *m0;
489
490 if ((m0 = clnp_reass(m, &src, &dst, &seg_part)) != NULL) {
491 m = m0;
492 clnp = mtod(m, struct clnp_fixed *);
493 INCSTAT(cns_reassembled);
494 } else {
495 return;
496 }
497 }
498
499 /*
500 * give the packet to the higher layer
501 *
502 * Note: the total length of packet
503 * is the total length field of the segmentation part,
504 * or, if absent, the segment length field of the
505 * header.
506 */
507 INCSTAT(cns_delivered);
508 switch (clnp->cnf_type & CNF_TYPE) {
509 case CLNP_ER:
510 /*
511 * This ER must have the er option.
512 * If the option is not present, discard datagram.
513 */
514 if (oidxp == NULL || oidxp->cni_er_reason == ER_INVALREAS) {
515 clnp_discard(m, GEN_HDRSYNTAX);
516 } else {
517 clnp_er_input(m, &src, oidxp->cni_er_reason);
518 }
519 break;
520
521 case CLNP_DT:
522 (*isosw[clnp_protox[ISOPROTO_TP]].pr_input)(m, &source, &target,
523 clnp->cnf_hdr_len, need_afrin);
524 break;
525
526 case CLNP_RAW:
527 case CLNP_ECR:
528 IFDEBUG(D_INPUT)
529 printf("clnp_input: raw input of %d bytes\n",
530 clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len);
531 ENDDEBUG
532 (*isosw[clnp_protox[ISOPROTO_RAW]].pr_input)(m, &source, &target,
533 clnp->cnf_hdr_len);
534 break;
535
536 case CLNP_EC:
537 IFDEBUG(D_INPUT)
538 printf("clnp_input: echoing packet\n");
539 ENDDEBUG
540 /*
541 * Switch the source and destination address,
542 */
543 hoff = (caddr_t)clnp + sizeof(struct clnp_fixed);
544 CLNP_INSERT_ADDR(hoff, src);
545 CLNP_INSERT_ADDR(hoff, dst);
546 clnp->cnf_type &= ~CNF_TYPE;
547 clnp->cnf_type |= CLNP_ECR;
548
549 /*
550 * Forward back to sender
551 */
552 clnp_forward(m, (int)
553 (clnp->cnf_type & CNF_SEG_OK ? seg_part.cng_tot_len : seg_len),
554 &src, oidxp, seg_off, 0);
555 break;
556
557 default:
558 printf("clnp_input: unknown clnp pkt type %d\n",
559 clnp->cnf_type & CNF_TYPE);
560 clnp_stat.cns_delivered--;
561 clnp_stat.cns_noproto++;
562 clnp_discard(m, GEN_HDRSYNTAX);
563 break;
564 }
565}
4c45483e 566#endif /* ISO */