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