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