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