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