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