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