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